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