Home | History | Annotate | Line # | Download | only in gemini
gemini_icu.c revision 1.5
      1  1.5  dyoung /*	$NetBSD: gemini_icu.c,v 1.5 2011/07/01 19:32:28 dyoung Exp $	*/
      2  1.1    matt 
      3  1.1    matt /* adapted from:
      4  1.1    matt  *	NetBSD: omap2_icu.c,v 1.4 2008/08/27 11:03:10 matt Exp
      5  1.1    matt  */
      6  1.1    matt 
      7  1.1    matt /*
      8  1.1    matt  * Define the SDP2430 specific information and then include the generic OMAP
      9  1.1    matt  * interrupt header.
     10  1.1    matt  */
     11  1.1    matt 
     12  1.1    matt /*
     13  1.1    matt  * Redistribution and use in source and binary forms, with or without
     14  1.1    matt  * modification, are permitted provided that the following conditions
     15  1.1    matt  * are met:
     16  1.1    matt  * 1. Redistributions of source code must retain this list of conditions
     17  1.1    matt  *    and the following disclaimer.
     18  1.1    matt  * 2. Redistributions in binary form must reproduce this list of conditions
     19  1.1    matt  *    and the following disclaimer in the documentation and/or other materials
     20  1.1    matt  *    provided with the distribution.
     21  1.1    matt  *
     22  1.1    matt  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     23  1.1    matt  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     24  1.1    matt  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
     25  1.1    matt  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     26  1.1    matt  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     27  1.1    matt  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     28  1.1    matt  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  1.1    matt  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     30  1.1    matt  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     31  1.1    matt  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  1.1    matt  */
     33  1.1    matt #include "opt_gemini.h"
     34  1.1    matt #include "geminiicu.h"
     35  1.1    matt 
     36  1.1    matt #define _INTR_PRIVATE
     37  1.1    matt 
     38  1.1    matt #include <sys/cdefs.h>
     39  1.5  dyoung __KERNEL_RCSID(0, "$NetBSD: gemini_icu.c,v 1.5 2011/07/01 19:32:28 dyoung Exp $");
     40  1.1    matt 
     41  1.1    matt #include <sys/param.h>
     42  1.1    matt #include <sys/evcnt.h>
     43  1.1    matt 
     44  1.1    matt #include <uvm/uvm_extern.h>
     45  1.1    matt 
     46  1.1    matt #include <machine/intr.h>
     47  1.5  dyoung #include <sys/bus.h>
     48  1.1    matt 
     49  1.1    matt #include <arm/cpu.h>
     50  1.1    matt #include <arm/armreg.h>
     51  1.1    matt #include <arm/cpufunc.h>
     52  1.1    matt #include <arm/atomic.h>
     53  1.1    matt 
     54  1.1    matt #include <arm/pic/picvar.h>
     55  1.1    matt 
     56  1.1    matt #include <arm/gemini/gemini_reg.h>
     57  1.1    matt #include <arm/gemini/gemini_obiovar.h>
     58  1.1    matt 
     59  1.1    matt 
     60  1.1    matt #define	INTC_READ(sc, o)		\
     61  1.1    matt 	bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (o))
     62  1.1    matt #define	INTC_WRITE(sc, o, v)	\
     63  1.1    matt 	bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (o), v)
     64  1.1    matt 
     65  1.1    matt static int geminiicu_match(device_t, cfdata_t, void *);
     66  1.1    matt static void geminiicu_attach(device_t, device_t, void *);
     67  1.1    matt 
     68  1.1    matt static void geminiicu_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     69  1.1    matt static void geminiicu_block_irqs(struct pic_softc *, size_t, uint32_t);
     70  1.1    matt static void geminiicu_establish_irq(struct pic_softc *, struct intrsource *);
     71  1.1    matt static void geminiicu_source_name(struct pic_softc *, int, char *, size_t);
     72  1.1    matt 
     73  1.1    matt static const struct pic_ops geminiicu_picops = {
     74  1.1    matt 	.pic_unblock_irqs = geminiicu_unblock_irqs,
     75  1.1    matt 	.pic_block_irqs = geminiicu_block_irqs,
     76  1.1    matt 	.pic_establish_irq = geminiicu_establish_irq,
     77  1.1    matt 	.pic_source_name = geminiicu_source_name,
     78  1.1    matt };
     79  1.1    matt 
     80  1.1    matt #define	PICTOSOFTC(pic)	\
     81  1.1    matt 	((void *)((uintptr_t)(pic) - offsetof(struct geminiicu_softc, sc_pic)))
     82  1.1    matt 
     83  1.1    matt static struct geminiicu_softc {
     84  1.1    matt 	device_t sc_dev;
     85  1.1    matt 	bus_space_tag_t sc_memt;
     86  1.1    matt 	bus_space_handle_t sc_memh;
     87  1.1    matt 	struct pic_softc sc_pic;
     88  1.1    matt 	uint32_t sc_enabled_mask;
     89  1.1    matt 	uint32_t sc_edge_mask;
     90  1.1    matt 	uint32_t sc_edge_rising_mask;
     91  1.1    matt 	uint32_t sc_edge_falling_mask;
     92  1.1    matt 	uint32_t sc_level_mask;
     93  1.1    matt 	uint32_t sc_level_hi_mask;
     94  1.1    matt 	uint32_t sc_level_lo_mask;
     95  1.1    matt } geminiicu_softc = {
     96  1.1    matt 	.sc_pic = {
     97  1.1    matt 		.pic_ops = &geminiicu_picops,
     98  1.1    matt 		.pic_maxsources = 32,
     99  1.1    matt 		.pic_name = "geminiicu",
    100  1.1    matt 	},
    101  1.1    matt };
    102  1.1    matt 
    103  1.2    matt static const char * const sources[32] = {
    104  1.2    matt 	"ipi(0)",	"gmac0(1)",	"gmac1(2)",	"wdt(3)",
    105  1.2    matt 	"ide0(4)",	"ide1(5)",	"raid(6)",	"crypto(7)",
    106  1.2    matt 	"pci(8)",	"dma(9)",	"usb0(10)",	"usb1(11)",
    107  1.2    matt 	"flash(12)",	"tve(13)",	"timer0(14)",	"timer1(15)",
    108  1.2    matt 	"timer2(16)",	"rtc(17)",	"uart(18)",	"lcd(19)",
    109  1.2    matt 	"lpc(20)",	"ssp(21)",	"gpio0(22)",	"gpio1(23)",
    110  1.2    matt 	"gpio2(24)",	"cir(25)",	"power(26)",	"irq 27",
    111  1.2    matt 	"irq 28",	"irq 29",	"usbc0(30)",	"usbc1(31)"
    112  1.2    matt };
    113  1.2    matt 
    114  1.2    matt static void geminiicu_source_name(struct pic_softc *pic, int irq,
    115  1.2    matt 	char *buf, size_t len)
    116  1.2    matt {
    117  1.2    matt 	KASSERT((unsigned int)irq < 32);
    118  1.2    matt 	strlcpy(buf, sources[irq], len);
    119  1.2    matt }
    120  1.2    matt 
    121  1.1    matt static void
    122  1.1    matt geminiicu_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
    123  1.1    matt {
    124  1.1    matt 	struct geminiicu_softc * const sc = PICTOSOFTC(pic);
    125  1.1    matt 	KASSERT(irqbase == 0 && (irq_mask & sc->sc_enabled_mask) == 0);
    126  1.1    matt 	sc->sc_enabled_mask |= irq_mask;
    127  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
    128  1.1    matt 	/*
    129  1.1    matt 	 * If this is a level source, ack it now.  If it's still asserted
    130  1.1    matt 	 * it'll come back.
    131  1.1    matt 	 */
    132  1.1    matt 	if (irq_mask & sc->sc_level_mask)
    133  1.1    matt 		INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR,
    134  1.1    matt 		    irq_mask & sc->sc_level_mask);
    135  1.1    matt }
    136  1.1    matt 
    137  1.1    matt static void
    138  1.1    matt geminiicu_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
    139  1.1    matt {
    140  1.1    matt 	struct geminiicu_softc * const sc = PICTOSOFTC(pic);
    141  1.1    matt 	KASSERT(irqbase == 0);
    142  1.1    matt 
    143  1.1    matt 	sc->sc_enabled_mask &= ~irq_mask;
    144  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
    145  1.1    matt 	/*
    146  1.1    matt 	 * If any of the source are edge triggered, ack them now so
    147  1.1    matt 	 * we won't lose them.
    148  1.1    matt 	 */
    149  1.1    matt 	if (irq_mask & sc->sc_edge_mask)
    150  1.1    matt 		INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR,
    151  1.1    matt 		    irq_mask & sc->sc_edge_mask);
    152  1.1    matt }
    153  1.1    matt 
    154  1.1    matt /*
    155  1.1    matt  * Called with interrupts disabled
    156  1.1    matt  */
    157  1.1    matt static int
    158  1.1    matt find_pending_irqs(struct geminiicu_softc *sc)
    159  1.1    matt {
    160  1.1    matt 	uint32_t pending = INTC_READ(sc, GEMINI_ICU_IRQ_STATUS);
    161  1.1    matt 
    162  1.1    matt 	KASSERT((sc->sc_enabled_mask & pending) == pending);
    163  1.1    matt 
    164  1.1    matt 	if (pending == 0)
    165  1.1    matt 		return 0;
    166  1.1    matt 
    167  1.1    matt 	return pic_mark_pending_sources(&sc->sc_pic, 0, pending);
    168  1.1    matt }
    169  1.1    matt 
    170  1.1    matt void
    171  1.1    matt gemini_irq_handler(void *frame)
    172  1.1    matt {
    173  1.1    matt 	struct cpu_info * const ci = curcpu();
    174  1.1    matt 	struct geminiicu_softc * const sc = &geminiicu_softc;
    175  1.1    matt 	const int oldipl = ci->ci_cpl;
    176  1.1    matt 	const uint32_t oldipl_mask = __BIT(oldipl);
    177  1.1    matt 	int ipl_mask = 0;
    178  1.1    matt 
    179  1.4    matt 	ci->ci_data.cpu_nintr++;
    180  1.1    matt 
    181  1.1    matt 	KASSERT(sc->sc_enabled_mask != 0);
    182  1.1    matt 
    183  1.1    matt 	ipl_mask = find_pending_irqs(sc);
    184  1.1    matt 
    185  1.1    matt 	/*
    186  1.1    matt 	 * Record the pending_ipls and deliver them if we can.
    187  1.1    matt 	 */
    188  1.1    matt 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    189  1.1    matt 		pic_do_pending_ints(I32_bit, oldipl, frame);
    190  1.1    matt }
    191  1.1    matt 
    192  1.1    matt void
    193  1.1    matt geminiicu_establish_irq(struct pic_softc *pic, struct intrsource *is)
    194  1.1    matt {
    195  1.1    matt 	struct geminiicu_softc * const sc = PICTOSOFTC(pic);
    196  1.1    matt 	const uint32_t irq_mask = __BIT(is->is_irq);
    197  1.1    matt 
    198  1.1    matt 	KASSERT(is->is_irq < 32);
    199  1.1    matt 
    200  1.1    matt 	sc->sc_enabled_mask &= ~irq_mask;
    201  1.1    matt 	/* Have to do with this interrupt disabled.  */
    202  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
    203  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR, irq_mask);
    204  1.1    matt 
    205  1.1    matt 	sc->sc_edge_rising_mask &= ~irq_mask;
    206  1.1    matt 	sc->sc_edge_falling_mask &= ~irq_mask;
    207  1.1    matt 	sc->sc_level_lo_mask &= ~irq_mask;
    208  1.1    matt 	sc->sc_level_hi_mask &= ~irq_mask;
    209  1.1    matt 
    210  1.1    matt         switch (is->is_type) {
    211  1.1    matt         case IST_LEVEL_LOW: sc->sc_level_lo_mask |= irq_mask; break;
    212  1.1    matt         case IST_LEVEL_HIGH: sc->sc_level_hi_mask |= irq_mask; break;
    213  1.1    matt         case IST_EDGE_FALLING: sc->sc_edge_falling_mask |= irq_mask; break;
    214  1.1    matt         case IST_EDGE_RISING: sc->sc_edge_rising_mask |= irq_mask; break;
    215  1.1    matt         }
    216  1.1    matt 
    217  1.1    matt         sc->sc_edge_mask = sc->sc_edge_rising_mask | sc->sc_edge_falling_mask;
    218  1.1    matt         sc->sc_level_mask = sc->sc_level_hi_mask|sc->sc_level_lo_mask;
    219  1.1    matt 
    220  1.1    matt 	/*
    221  1.1    matt 	 * Set the new interrupt mode.
    222  1.1    matt 	 */
    223  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGMODE, sc->sc_edge_mask);
    224  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGLEVEL,
    225  1.1    matt 	    sc->sc_level_lo_mask | sc->sc_edge_falling_mask);
    226  1.1    matt }
    227  1.1    matt 
    228  1.1    matt int
    229  1.1    matt geminiicu_match(device_t parent, cfdata_t cf, void *aux)
    230  1.1    matt {
    231  1.1    matt 	struct obio_attach_args * const oa = aux;
    232  1.1    matt 
    233  1.1    matt #if defined(SL3516)
    234  1.1    matt 	if ((oa->obio_addr == GEMINI_IC0_BASE)
    235  1.1    matt 	||  (oa->obio_addr == GEMINI_IC1_BASE))
    236  1.1    matt 		return 1;
    237  1.1    matt 
    238  1.1    matt 	return 0;
    239  1.1    matt #else
    240  1.1    matt #error unsupported GEMINI variant
    241  1.1    matt #endif
    242  1.1    matt }
    243  1.1    matt 
    244  1.1    matt void
    245  1.1    matt geminiicu_attach(device_t parent, device_t self, void *aux)
    246  1.1    matt {
    247  1.1    matt 	struct obio_attach_args * const oa = aux;
    248  1.1    matt 	struct geminiicu_softc * const sc = &geminiicu_softc;
    249  1.1    matt 	int error;
    250  1.1    matt 
    251  1.1    matt 	aprint_normal("\n");
    252  1.1    matt 
    253  1.1    matt 	sc->sc_memt = oa->obio_iot;
    254  1.1    matt 
    255  1.1    matt 	error = bus_space_map(sc->sc_memt, oa->obio_addr, 0x1000, 0,
    256  1.1    matt 	    &sc->sc_memh);
    257  1.1    matt 	if (error)
    258  1.1    matt 		panic("failed to map interrupt registers: %d", error);
    259  1.1    matt 
    260  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, 0);
    261  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR, 0xffffffff);
    262  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGMODE, 0);
    263  1.1    matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGLEVEL, 0xffffffff);
    264  1.1    matt 
    265  1.1    matt 	sc->sc_dev = self;
    266  1.1    matt 	self->dv_private = sc;
    267  1.1    matt 
    268  1.1    matt 	pic_add(&sc->sc_pic, 0);
    269  1.1    matt }
    270  1.1    matt 
    271  1.1    matt CFATTACH_DECL_NEW(geminiicu,
    272  1.1    matt     0,
    273  1.1    matt     geminiicu_match, geminiicu_attach,
    274  1.1    matt     NULL, NULL);
    275