Home | History | Annotate | Line # | Download | only in s3c2xx0
      1 /*-
      2  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to The NetBSD Foundation
      6  * by Paul Fleischer <paul (at) xpg.dk>
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 /* Derived from s3c2410_intr.c */
     31 /*
     32  * Copyright (c) 2003  Genetec corporation.  All rights reserved.
     33  * Written by Hiroyuki Bessho for Genetec corporation.
     34  *
     35  * Redistribution and use in source and binary forms, with or without
     36  * modification, are permitted provided that the following conditions
     37  * are met:
     38  * 1. Redistributions of source code must retain the above copyright
     39  *    notice, this list of conditions and the following disclaimer.
     40  * 2. Redistributions in binary form must reproduce the above copyright
     41  *    notice, this list of conditions and the following disclaimer in the
     42  *    documentation and/or other materials provided with the distribution.
     43  * 3. The name of Genetec corporation may not be used to endorse
     44  *    or promote products derived from this software without specific prior
     45  *    written permission.
     46  *
     47  * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
     48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORP.
     51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     57  * POSSIBILITY OF SUCH DAMAGE.
     58  */
     59 
     60 /*
     61  * IRQ handler for Samsung S3C2440 processor.
     62  * It has integrated interrupt controller.
     63  */
     64 
     65 #include <sys/cdefs.h>
     66 __KERNEL_RCSID(0, "$NetBSD: s3c2440_intr.c,v 1.2 2022/09/27 06:36:43 skrll Exp $");
     67 
     68 #include <sys/param.h>
     69 #include <sys/systm.h>
     70 #include <sys/atomic.h>
     71 #include <sys/bus.h>
     72 #include <machine/intr.h>
     73 #include <arm/cpufunc.h>
     74 
     75 #include <arm/s3c2xx0/s3c2440reg.h>
     76 #include <arm/s3c2xx0/s3c2440var.h>
     77 
     78 /*
     79  * interrupt dispatch table.
     80  */
     81 
     82 struct s3c2xx0_intr_dispatch handler[ICU_LEN];
     83 
     84 
     85 volatile int intr_mask;
     86 #ifdef __HAVE_FAST_SOFTINTS
     87 volatile int softint_pending;
     88 volatile int soft_intr_mask;
     89 #endif
     90 volatile int global_intr_mask = 0; /* mask some interrupts at all spl level */
     91 
     92 /* interrupt masks for each level */
     93 int s3c2xx0_imask[NIPL];
     94 int s3c2xx0_ilevel[ICU_LEN];
     95 #ifdef __HAVE_FAST_SOFTINTS
     96 int s3c24x0_soft_imask[NIPL];
     97 #endif
     98 
     99 vaddr_t intctl_base;		/* interrupt controller registers */
    100 #define icreg(offset) \
    101 	(*(volatile uint32_t *)(intctl_base+(offset)))
    102 
    103 #ifdef __HAVE_FAST_SOFTINTS
    104 /*
    105  * Map a software interrupt queue to an interrupt priority level.
    106  */
    107 static const int si_to_ipl[] = {
    108 	[SI_SOFTBIO]	= IPL_SOFTBIO,
    109 	[SI_SOFTCLOCK]	= IPL_SOFTCLOCK,
    110 	[SI_SOFTNET]	= IPL_SOFTNET,
    111 	[SI_SOFTSERIAL] = IPL_SOFTSERIAL,
    112 };
    113 #endif
    114 
    115 #define PENDING_CLEAR_MASK	(~0)
    116 
    117 /*
    118  * called from irq_entry.
    119  */
    120 void s3c2440_irq_handler(struct clockframe *);
    121 void
    122 s3c2440_irq_handler(struct clockframe *frame)
    123 {
    124 	uint32_t irqbits;
    125 	int irqno;
    126 	int saved_spl_level;
    127 	struct cpu_info * const ci = curcpu();
    128 
    129 	saved_spl_level = curcpl();
    130 
    131 #ifdef	DIAGNOSTIC
    132 	if (curcpu()->ci_intr_depth > 10)
    133 		panic("nested intr too deep");
    134 #endif
    135 
    136 	while ((irqbits = icreg(INTCTL_INTPND)) != 0) {
    137 		/* Note: Only one bit in INTPND register is set */
    138 
    139 		irqno = icreg(INTCTL_INTOFFSET);
    140 
    141 #ifdef	DIAGNOSTIC
    142 		if (__predict_false((irqbits & (1<<irqno)) == 0)) {
    143 			/* This shouldn't happen */
    144 			printf("INTOFFSET=%d, INTPND=%x\n", irqno, irqbits);
    145 			break;
    146 		}
    147 #endif
    148 		/* raise spl to stop interrupts of lower priorities */
    149 		if (saved_spl_level < handler[irqno].level)
    150 			s3c2xx0_setipl(handler[irqno].level);
    151 
    152 		/* clear pending bit */
    153 		icreg(INTCTL_SRCPND) = PENDING_CLEAR_MASK & (1 << irqno);
    154 		icreg(INTCTL_INTPND) = PENDING_CLEAR_MASK & (1 << irqno);
    155 
    156 		handler[irqno].ev.ev_count++;
    157 		ci->ci_data.cpu_nintr++;
    158 
    159 		enable_interrupts(I32_bit); /* allow nested interrupts */
    160 
    161 		(*handler[irqno].func) (
    162 		    handler[irqno].cookie == 0
    163 		    ? frame : handler[irqno].cookie);
    164 
    165 		disable_interrupts(I32_bit);
    166 
    167 		/* restore spl to that was when this interrupt happen */
    168 		s3c2xx0_setipl(saved_spl_level);
    169 
    170 	}
    171 
    172 #ifdef __HAVE_FAST_SOFTINTS
    173 	cpu_dosoftints();
    174 #endif
    175 }
    176 
    177 /*
    178  * Handler for main IRQ of cascaded interrupts.
    179  */
    180 static int
    181 cascade_irq_handler(void *cookie)
    182 {
    183 	int index = (int)cookie - 1;
    184 	uint32_t irqbits;
    185 	int irqno, i;
    186 	int save = disable_interrupts(I32_bit);
    187 
    188 	KASSERT(0 <= index && index <= 3);
    189 
    190 	irqbits = icreg(INTCTL_SUBSRCPND) &
    191 	    ~icreg(INTCTL_INTSUBMSK) & (0x07 << (3*index));
    192 
    193 	for (irqno = 3*index; irqbits; ++irqno) {
    194 		if ((irqbits & (1<<irqno)) == 0)
    195 			continue;
    196 
    197 		/* clear pending bit */
    198 		irqbits &= ~(1<<irqno);
    199 		icreg(INTCTL_SUBSRCPND) = (1 << irqno);
    200 
    201 		/* allow nested interrupts. SPL is already set
    202 		 * correctly by main handler. */
    203 		restore_interrupts(save);
    204 
    205 		i = S3C2440_SUBIRQ_MIN + irqno;
    206 		(* handler[i].func)(handler[i].cookie);
    207 
    208 		disable_interrupts(I32_bit);
    209 	}
    210 
    211 	return 1;
    212 }
    213 
    214 
    215 static const uint8_t subirq_to_main[] = {
    216 	S3C2440_INT_UART0,
    217 	S3C2440_INT_UART0,
    218 	S3C2440_INT_UART0,
    219 	S3C2440_INT_UART1,
    220 	S3C2440_INT_UART1,
    221 	S3C2440_INT_UART1,
    222 	S3C2440_INT_UART2,
    223 	S3C2440_INT_UART2,
    224 	S3C2440_INT_UART2,
    225 	S3C24X0_INT_ADCTC,
    226 	S3C24X0_INT_ADCTC,
    227 };
    228 
    229 void *
    230 s3c24x0_intr_establish(int irqno, int level, int type,
    231     int (* func) (void *), void *cookie)
    232 {
    233 	int save;
    234 
    235 	if (irqno < 0 || irqno >= ICU_LEN ||
    236 	    type < IST_NONE || IST_EDGE_BOTH < type)
    237 		panic("intr_establish: bogus irq or type");
    238 
    239 	save = disable_interrupts(I32_bit);
    240 
    241 	handler[irqno].cookie = cookie;
    242 	handler[irqno].func = func;
    243 	handler[irqno].level = level;
    244 
    245 	if (irqno >= S3C2440_SUBIRQ_MIN) {
    246 		/* cascaded interrupts. */
    247 		int main_irqno;
    248 		int i = (irqno - S3C2440_SUBIRQ_MIN);
    249 
    250 		main_irqno = subirq_to_main[i];
    251 
    252 		/* establish main irq if first time
    253 		 * be careful that cookie shouldn't be 0 */
    254 		if (handler[main_irqno].func != cascade_irq_handler)
    255 			s3c24x0_intr_establish(main_irqno, level, type,
    256 			    cascade_irq_handler, (void *)((i/3) + 1));
    257 
    258 		/* unmask it in submask register */
    259 		icreg(INTCTL_INTSUBMSK) &= ~(1<<i);
    260 
    261 		restore_interrupts(save);
    262 		return &handler[irqno];
    263 	}
    264 
    265 	s3c2xx0_update_intr_masks(irqno, level);
    266 
    267 	/*
    268 	 * set trigger type for external interrupts 0..3
    269 	 */
    270 	if (irqno <= S3C24X0_INT_EXT(3)) {
    271 		/*
    272 		 * Update external interrupt control
    273 		 */
    274 		s3c2440_setup_extint(irqno, type);
    275 	}
    276 
    277 	s3c2xx0_setipl(curcpl());
    278 
    279 	restore_interrupts(save);
    280 
    281 	return &handler[irqno];
    282 }
    283 
    284 
    285 static void
    286 init_interrupt_masks(void)
    287 {
    288 	int i;
    289 
    290 	for (i=0; i < NIPL; ++i)
    291 		s3c2xx0_imask[i] = 0;
    292 
    293 #ifdef __HAVE_FAST_SOFTINTS
    294 	s3c24x0_soft_imask[IPL_NONE] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
    295 		SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK) |
    296 		SI_TO_IRQBIT(SI_SOFT);
    297 
    298 	s3c24x0_soft_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
    299 		SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK);
    300 
    301 	/*
    302 	 * splsoftclock() is the only interface that users of the
    303 	 * generic software interrupt facility have to block their
    304 	 * soft intrs, so splsoftclock() must also block IPL_SOFT.
    305 	 */
    306 	s3c24x0_soft_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
    307 		SI_TO_IRQBIT(SI_SOFTNET);
    308 
    309 	/*
    310 	 * splsoftnet() must also block splsoftclock(), since we don't
    311 	 * want timer-driven network events to occur while we're
    312 	 * processing incoming packets.
    313 	 */
    314 	s3c24x0_soft_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTSERIAL);
    315 
    316 	for (i = IPL_BIO; i < IPL_SOFTSERIAL; ++i)
    317 		s3c24x0_soft_imask[i] = SI_TO_IRQBIT(SI_SOFTSERIAL);
    318 #endif
    319 }
    320 
    321 void
    322 s3c2440_intr_init(struct s3c24x0_softc *sc)
    323 {
    324 	intctl_base = (vaddr_t) bus_space_vaddr(sc->sc_sx.sc_iot,
    325 	    sc->sc_sx.sc_intctl_ioh);
    326 
    327 	s3c2xx0_intr_mask_reg = (uint32_t *)(intctl_base + INTCTL_INTMSK);
    328 
    329 	/* clear all pending interrupt */
    330 	icreg(INTCTL_SRCPND) = ~0;
    331 	icreg(INTCTL_INTPND) = ~0;
    332 
    333 	/* mask all sub interrupts */
    334 	icreg(INTCTL_INTSUBMSK) = 0x7ff;
    335 
    336 	init_interrupt_masks();
    337 
    338 	s3c2xx0_intr_init(handler, ICU_LEN);
    339 
    340 }
    341 
    342 
    343 /*
    344  * mask/unmask sub interrupts
    345  */
    346 void
    347 s3c2440_mask_subinterrupts(int bits)
    348 {
    349 	int psw = disable_interrupts(IF32_bits);
    350 	icreg(INTCTL_INTSUBMSK) |= bits;
    351 	restore_interrupts(psw);
    352 
    353 }
    354 
    355 void
    356 s3c2440_unmask_subinterrupts(int bits)
    357 {
    358 	int psw = disable_interrupts(IF32_bits);
    359 	icreg(INTCTL_INTSUBMSK) &= ~bits;
    360 	restore_interrupts(psw);
    361 
    362 }
    363 
    364 /*
    365  * Update external interrupt control
    366  */
    367 static const u_char s3c24x0_ist[] = {
    368 	EXTINTR_LOW,		/* NONE */
    369 	EXTINTR_FALLING,	/* PULSE */
    370 	EXTINTR_FALLING,	/* EDGE */
    371 	EXTINTR_LOW,		/* LEVEL */
    372 	EXTINTR_HIGH,
    373 	EXTINTR_RISING,
    374 	EXTINTR_BOTH,
    375 };
    376 
    377 void
    378 s3c2440_setup_extint(int extint, int type)
    379 {
    380         uint32_t reg;
    381         u_int   trig;
    382         int     i = extint % 8;
    383         int     regidx = extint/8;      /* GPIO_EXTINT[0:2] */
    384 	int	save;
    385 	uint32_t gpio;
    386 	uint32_t offset;
    387 
    388         trig = s3c24x0_ist[type];
    389 
    390 	save = disable_interrupts(I32_bit);
    391 
    392         reg = bus_space_read_4(s3c2xx0_softc->sc_iot,
    393             s3c2xx0_softc->sc_gpio_ioh,
    394             GPIO_EXTINT(regidx));
    395 
    396         reg = reg & ~(0x07 << (4*i));
    397         reg |= trig << (4*i);
    398 
    399         bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
    400             GPIO_EXTINT(regidx), reg);
    401 
    402 	/* Setup GPIO-pin to serve as interrupt */
    403 	if (extint < 8 ) {
    404 	  gpio = GPIO_PFCON;
    405 	  offset = extint;
    406 	} else {
    407 	  gpio = GPIO_PGCON;
    408 	  offset = 8-extint;
    409 	}
    410 	reg = bus_space_read_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
    411 				 gpio);
    412 	reg = GPIO_SET_FUNC(reg, offset, 2);
    413 	bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
    414 			  gpio, reg);
    415 
    416 
    417 	restore_interrupts(save);
    418 }
    419