Home | History | Annotate | Line # | Download | only in gemini
gemini_icu.c revision 1.7
      1  1.7  riastrad /*	$NetBSD: gemini_icu.c,v 1.7 2022/03/03 06:26:29 riastradh 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.7  riastrad __KERNEL_RCSID(0, "$NetBSD: gemini_icu.c,v 1.7 2022/03/03 06:26:29 riastradh 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 
     53  1.1      matt #include <arm/pic/picvar.h>
     54  1.1      matt 
     55  1.1      matt #include <arm/gemini/gemini_reg.h>
     56  1.1      matt #include <arm/gemini/gemini_obiovar.h>
     57  1.1      matt 
     58  1.1      matt 
     59  1.1      matt #define	INTC_READ(sc, o)		\
     60  1.1      matt 	bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (o))
     61  1.1      matt #define	INTC_WRITE(sc, o, v)	\
     62  1.1      matt 	bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (o), v)
     63  1.1      matt 
     64  1.1      matt static int geminiicu_match(device_t, cfdata_t, void *);
     65  1.1      matt static void geminiicu_attach(device_t, device_t, void *);
     66  1.1      matt 
     67  1.1      matt static void geminiicu_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     68  1.1      matt static void geminiicu_block_irqs(struct pic_softc *, size_t, uint32_t);
     69  1.1      matt static void geminiicu_establish_irq(struct pic_softc *, struct intrsource *);
     70  1.1      matt static void geminiicu_source_name(struct pic_softc *, int, char *, size_t);
     71  1.1      matt 
     72  1.1      matt static const struct pic_ops geminiicu_picops = {
     73  1.1      matt 	.pic_unblock_irqs = geminiicu_unblock_irqs,
     74  1.1      matt 	.pic_block_irqs = geminiicu_block_irqs,
     75  1.1      matt 	.pic_establish_irq = geminiicu_establish_irq,
     76  1.1      matt 	.pic_source_name = geminiicu_source_name,
     77  1.1      matt };
     78  1.1      matt 
     79  1.1      matt #define	PICTOSOFTC(pic)	\
     80  1.1      matt 	((void *)((uintptr_t)(pic) - offsetof(struct geminiicu_softc, sc_pic)))
     81  1.1      matt 
     82  1.1      matt static struct geminiicu_softc {
     83  1.1      matt 	device_t sc_dev;
     84  1.1      matt 	bus_space_tag_t sc_memt;
     85  1.1      matt 	bus_space_handle_t sc_memh;
     86  1.1      matt 	struct pic_softc sc_pic;
     87  1.1      matt 	uint32_t sc_enabled_mask;
     88  1.1      matt 	uint32_t sc_edge_mask;
     89  1.1      matt 	uint32_t sc_edge_rising_mask;
     90  1.1      matt 	uint32_t sc_edge_falling_mask;
     91  1.1      matt 	uint32_t sc_level_mask;
     92  1.1      matt 	uint32_t sc_level_hi_mask;
     93  1.1      matt 	uint32_t sc_level_lo_mask;
     94  1.1      matt } geminiicu_softc = {
     95  1.1      matt 	.sc_pic = {
     96  1.1      matt 		.pic_ops = &geminiicu_picops,
     97  1.1      matt 		.pic_maxsources = 32,
     98  1.1      matt 		.pic_name = "geminiicu",
     99  1.1      matt 	},
    100  1.1      matt };
    101  1.1      matt 
    102  1.2      matt static const char * const sources[32] = {
    103  1.2      matt 	"ipi(0)",	"gmac0(1)",	"gmac1(2)",	"wdt(3)",
    104  1.2      matt 	"ide0(4)",	"ide1(5)",	"raid(6)",	"crypto(7)",
    105  1.2      matt 	"pci(8)",	"dma(9)",	"usb0(10)",	"usb1(11)",
    106  1.2      matt 	"flash(12)",	"tve(13)",	"timer0(14)",	"timer1(15)",
    107  1.2      matt 	"timer2(16)",	"rtc(17)",	"uart(18)",	"lcd(19)",
    108  1.2      matt 	"lpc(20)",	"ssp(21)",	"gpio0(22)",	"gpio1(23)",
    109  1.2      matt 	"gpio2(24)",	"cir(25)",	"power(26)",	"irq 27",
    110  1.2      matt 	"irq 28",	"irq 29",	"usbc0(30)",	"usbc1(31)"
    111  1.2      matt };
    112  1.2      matt 
    113  1.2      matt static void geminiicu_source_name(struct pic_softc *pic, int irq,
    114  1.2      matt 	char *buf, size_t len)
    115  1.2      matt {
    116  1.2      matt 	KASSERT((unsigned int)irq < 32);
    117  1.2      matt 	strlcpy(buf, sources[irq], len);
    118  1.2      matt }
    119  1.2      matt 
    120  1.1      matt static void
    121  1.1      matt geminiicu_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
    122  1.1      matt {
    123  1.1      matt 	struct geminiicu_softc * const sc = PICTOSOFTC(pic);
    124  1.1      matt 	KASSERT(irqbase == 0 && (irq_mask & sc->sc_enabled_mask) == 0);
    125  1.1      matt 	sc->sc_enabled_mask |= irq_mask;
    126  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
    127  1.1      matt 	/*
    128  1.1      matt 	 * If this is a level source, ack it now.  If it's still asserted
    129  1.1      matt 	 * it'll come back.
    130  1.1      matt 	 */
    131  1.1      matt 	if (irq_mask & sc->sc_level_mask)
    132  1.1      matt 		INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR,
    133  1.1      matt 		    irq_mask & sc->sc_level_mask);
    134  1.1      matt }
    135  1.1      matt 
    136  1.1      matt static void
    137  1.1      matt geminiicu_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
    138  1.1      matt {
    139  1.1      matt 	struct geminiicu_softc * const sc = PICTOSOFTC(pic);
    140  1.1      matt 	KASSERT(irqbase == 0);
    141  1.1      matt 
    142  1.1      matt 	sc->sc_enabled_mask &= ~irq_mask;
    143  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
    144  1.1      matt 	/*
    145  1.1      matt 	 * If any of the source are edge triggered, ack them now so
    146  1.1      matt 	 * we won't lose them.
    147  1.1      matt 	 */
    148  1.1      matt 	if (irq_mask & sc->sc_edge_mask)
    149  1.1      matt 		INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR,
    150  1.1      matt 		    irq_mask & sc->sc_edge_mask);
    151  1.1      matt }
    152  1.1      matt 
    153  1.1      matt /*
    154  1.1      matt  * Called with interrupts disabled
    155  1.1      matt  */
    156  1.1      matt static int
    157  1.1      matt find_pending_irqs(struct geminiicu_softc *sc)
    158  1.1      matt {
    159  1.1      matt 	uint32_t pending = INTC_READ(sc, GEMINI_ICU_IRQ_STATUS);
    160  1.1      matt 
    161  1.1      matt 	KASSERT((sc->sc_enabled_mask & pending) == pending);
    162  1.1      matt 
    163  1.1      matt 	if (pending == 0)
    164  1.1      matt 		return 0;
    165  1.1      matt 
    166  1.1      matt 	return pic_mark_pending_sources(&sc->sc_pic, 0, pending);
    167  1.1      matt }
    168  1.1      matt 
    169  1.1      matt void
    170  1.1      matt gemini_irq_handler(void *frame)
    171  1.1      matt {
    172  1.1      matt 	struct cpu_info * const ci = curcpu();
    173  1.1      matt 	struct geminiicu_softc * const sc = &geminiicu_softc;
    174  1.1      matt 	const int oldipl = ci->ci_cpl;
    175  1.1      matt 	const uint32_t oldipl_mask = __BIT(oldipl);
    176  1.1      matt 	int ipl_mask = 0;
    177  1.1      matt 
    178  1.4      matt 	ci->ci_data.cpu_nintr++;
    179  1.1      matt 
    180  1.1      matt 	KASSERT(sc->sc_enabled_mask != 0);
    181  1.1      matt 
    182  1.1      matt 	ipl_mask = find_pending_irqs(sc);
    183  1.1      matt 
    184  1.1      matt 	/*
    185  1.1      matt 	 * Record the pending_ipls and deliver them if we can.
    186  1.1      matt 	 */
    187  1.1      matt 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    188  1.1      matt 		pic_do_pending_ints(I32_bit, oldipl, frame);
    189  1.1      matt }
    190  1.1      matt 
    191  1.1      matt void
    192  1.1      matt geminiicu_establish_irq(struct pic_softc *pic, struct intrsource *is)
    193  1.1      matt {
    194  1.1      matt 	struct geminiicu_softc * const sc = PICTOSOFTC(pic);
    195  1.1      matt 	const uint32_t irq_mask = __BIT(is->is_irq);
    196  1.1      matt 
    197  1.1      matt 	KASSERT(is->is_irq < 32);
    198  1.1      matt 
    199  1.1      matt 	sc->sc_enabled_mask &= ~irq_mask;
    200  1.1      matt 	/* Have to do with this interrupt disabled.  */
    201  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, sc->sc_enabled_mask);
    202  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR, irq_mask);
    203  1.1      matt 
    204  1.1      matt 	sc->sc_edge_rising_mask &= ~irq_mask;
    205  1.1      matt 	sc->sc_edge_falling_mask &= ~irq_mask;
    206  1.1      matt 	sc->sc_level_lo_mask &= ~irq_mask;
    207  1.1      matt 	sc->sc_level_hi_mask &= ~irq_mask;
    208  1.1      matt 
    209  1.1      matt         switch (is->is_type) {
    210  1.1      matt         case IST_LEVEL_LOW: sc->sc_level_lo_mask |= irq_mask; break;
    211  1.1      matt         case IST_LEVEL_HIGH: sc->sc_level_hi_mask |= irq_mask; break;
    212  1.1      matt         case IST_EDGE_FALLING: sc->sc_edge_falling_mask |= irq_mask; break;
    213  1.1      matt         case IST_EDGE_RISING: sc->sc_edge_rising_mask |= irq_mask; break;
    214  1.1      matt         }
    215  1.1      matt 
    216  1.1      matt         sc->sc_edge_mask = sc->sc_edge_rising_mask | sc->sc_edge_falling_mask;
    217  1.1      matt         sc->sc_level_mask = sc->sc_level_hi_mask|sc->sc_level_lo_mask;
    218  1.1      matt 
    219  1.1      matt 	/*
    220  1.1      matt 	 * Set the new interrupt mode.
    221  1.1      matt 	 */
    222  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGMODE, sc->sc_edge_mask);
    223  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGLEVEL,
    224  1.1      matt 	    sc->sc_level_lo_mask | sc->sc_edge_falling_mask);
    225  1.1      matt }
    226  1.1      matt 
    227  1.1      matt int
    228  1.1      matt geminiicu_match(device_t parent, cfdata_t cf, void *aux)
    229  1.1      matt {
    230  1.1      matt 	struct obio_attach_args * const oa = aux;
    231  1.1      matt 
    232  1.1      matt #if defined(SL3516)
    233  1.1      matt 	if ((oa->obio_addr == GEMINI_IC0_BASE)
    234  1.1      matt 	||  (oa->obio_addr == GEMINI_IC1_BASE))
    235  1.1      matt 		return 1;
    236  1.1      matt 
    237  1.1      matt 	return 0;
    238  1.1      matt #else
    239  1.1      matt #error unsupported GEMINI variant
    240  1.1      matt #endif
    241  1.1      matt }
    242  1.1      matt 
    243  1.1      matt void
    244  1.1      matt geminiicu_attach(device_t parent, device_t self, void *aux)
    245  1.1      matt {
    246  1.1      matt 	struct obio_attach_args * const oa = aux;
    247  1.1      matt 	struct geminiicu_softc * const sc = &geminiicu_softc;
    248  1.1      matt 	int error;
    249  1.1      matt 
    250  1.1      matt 	aprint_normal("\n");
    251  1.1      matt 
    252  1.1      matt 	sc->sc_memt = oa->obio_iot;
    253  1.1      matt 
    254  1.1      matt 	error = bus_space_map(sc->sc_memt, oa->obio_addr, 0x1000, 0,
    255  1.1      matt 	    &sc->sc_memh);
    256  1.1      matt 	if (error)
    257  1.1      matt 		panic("failed to map interrupt registers: %d", error);
    258  1.1      matt 
    259  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_ENABLE, 0);
    260  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_CLEAR, 0xffffffff);
    261  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGMODE, 0);
    262  1.1      matt 	INTC_WRITE(sc, GEMINI_ICU_IRQ_TRIGLEVEL, 0xffffffff);
    263  1.1      matt 
    264  1.1      matt 	sc->sc_dev = self;
    265  1.7  riastrad 	device_set_private(self, sc);
    266  1.1      matt 
    267  1.1      matt 	pic_add(&sc->sc_pic, 0);
    268  1.1      matt }
    269  1.1      matt 
    270  1.1      matt CFATTACH_DECL_NEW(geminiicu,
    271  1.1      matt     0,
    272  1.1      matt     geminiicu_match, geminiicu_attach,
    273  1.1      matt     NULL, NULL);
    274