xref: /netbsd-src/sys/arch/arm/s3c2xx0/s3c2800_intr.c (revision f82ca6eefb335bf699131a4ebe4cc00c8911db8a)
1*f82ca6eeSskrll /* $NetBSD: s3c2800_intr.c,v 1.14 2022/09/27 06:36:43 skrll Exp $ */
2d6cadcddSbsh 
3d6cadcddSbsh /*
4d6cadcddSbsh  * Copyright (c) 2002 Fujitsu Component Limited
5d6cadcddSbsh  * Copyright (c) 2002 Genetec Corporation
6d6cadcddSbsh  * All rights reserved.
7d6cadcddSbsh  *
8d6cadcddSbsh  * Redistribution and use in source and binary forms, with or without
9d6cadcddSbsh  * modification, are permitted provided that the following conditions
10d6cadcddSbsh  * are met:
11d6cadcddSbsh  * 1. Redistributions of source code must retain the above copyright
12d6cadcddSbsh  *    notice, this list of conditions and the following disclaimer.
13d6cadcddSbsh  * 2. Redistributions in binary form must reproduce the above copyright
14d6cadcddSbsh  *    notice, this list of conditions and the following disclaimer in the
15d6cadcddSbsh  *    documentation and/or other materials provided with the distribution.
16d6cadcddSbsh  * 3. Neither the name of The Fujitsu Component Limited nor the name of
17d6cadcddSbsh  *    Genetec corporation may not be used to endorse or promote products
18d6cadcddSbsh  *    derived from this software without specific prior written permission.
19d6cadcddSbsh  *
20d6cadcddSbsh  * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
21d6cadcddSbsh  * CORPORATION ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22d6cadcddSbsh  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23d6cadcddSbsh  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24d6cadcddSbsh  * DISCLAIMED.  IN NO EVENT SHALL FUJITSU COMPONENT LIMITED OR GENETEC
25d6cadcddSbsh  * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26d6cadcddSbsh  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27d6cadcddSbsh  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28d6cadcddSbsh  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29d6cadcddSbsh  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30d6cadcddSbsh  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31d6cadcddSbsh  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32d6cadcddSbsh  * SUCH DAMAGE.
33d6cadcddSbsh  */
34d6cadcddSbsh 
35d6cadcddSbsh /*
36d6cadcddSbsh  * IRQ handler for Samsung S3C2800 processor.
37d6cadcddSbsh  * It has integrated interrupt controller.
38d6cadcddSbsh  */
3908716eaeSlukem 
4008716eaeSlukem #include <sys/cdefs.h>
41*f82ca6eeSskrll __KERNEL_RCSID(0, "$NetBSD: s3c2800_intr.c,v 1.14 2022/09/27 06:36:43 skrll Exp $");
4208716eaeSlukem 
43d6cadcddSbsh #include <sys/param.h>
44d6cadcddSbsh #include <sys/systm.h>
456a66466fSmatt 
46ed9977b1Sdyoung #include <sys/bus.h>
47d6cadcddSbsh #include <machine/intr.h>
486a66466fSmatt 
49d6cadcddSbsh #include <arm/cpufunc.h>
50d6cadcddSbsh 
51d6cadcddSbsh #include <arm/s3c2xx0/s3c2800reg.h>
52d6cadcddSbsh #include <arm/s3c2xx0/s3c2800var.h>
53d6cadcddSbsh 
54d6cadcddSbsh /*
55d6cadcddSbsh  * interrupt dispatch table.
56d6cadcddSbsh  */
57d6cadcddSbsh 
58d6cadcddSbsh struct s3c2xx0_intr_dispatch handler[ICU_LEN];
59d6cadcddSbsh 
605f1c88d7Sperry volatile int intr_mask;    /* XXX: does this need to be volatile? */
615f1c88d7Sperry volatile int global_intr_mask = 0; /* mask some interrupts at all spl level */
62d6cadcddSbsh 
63d6cadcddSbsh /* interrupt masks for each level */
64d6cadcddSbsh int s3c2xx0_imask[NIPL];
65d6cadcddSbsh int s3c2xx0_ilevel[ICU_LEN];
66d6cadcddSbsh 
67d6cadcddSbsh vaddr_t intctl_base;		/* interrupt controller registers */
68d6cadcddSbsh #define icreg(offset) \
69d6cadcddSbsh 	(*(volatile uint32_t *)(intctl_base+(offset)))
70d6cadcddSbsh 
71a99b5e08Sbsh /*
72a99b5e08Sbsh  *   Clearing interrupt pending bits affects some built-in
73a99b5e08Sbsh  * peripherals.  For example, IIC starts transmitting next data when
74a99b5e08Sbsh  * its interrupt pending bit is cleared.
75a99b5e08Sbsh  *   We need to leave those bits to peripheral handlers.
76a99b5e08Sbsh  */
77a99b5e08Sbsh #define PENDING_CLEAR_MASK	(~((1<<S3C2800_INT_IIC0)|(1<<S3C2800_INT_IIC1)))
78a99b5e08Sbsh 
79d6cadcddSbsh /*
80d6cadcddSbsh  * called from irq_entry.
81d6cadcddSbsh  */
82d6cadcddSbsh void s3c2800_irq_handler(struct clockframe *);
83d6cadcddSbsh void
s3c2800_irq_handler(struct clockframe * frame)84d6cadcddSbsh s3c2800_irq_handler(struct clockframe *frame)
85d6cadcddSbsh {
86d6cadcddSbsh 	uint32_t irqbits;
87d6cadcddSbsh 	int irqno;
88d6cadcddSbsh 	int saved_spl_level;
89d6cadcddSbsh 
90825088edSmatt 	saved_spl_level = curcpl();
91d6cadcddSbsh 
92675f6328Sbsh 	while ((irqbits = icreg(INTCTL_IRQPND) & ICU_INT_HWMASK) != 0) {
93d6cadcddSbsh 
94675f6328Sbsh 		for (irqno = ICU_LEN-1; irqno >= 0; --irqno)
95675f6328Sbsh 			if (irqbits & (1<<irqno))
96675f6328Sbsh 				break;
97675f6328Sbsh 
98675f6328Sbsh 		if (irqno < 0)
99675f6328Sbsh 			break;
100675f6328Sbsh 
101d6cadcddSbsh 		/* raise spl to stop interrupts of lower priorities */
102d6cadcddSbsh 		if (saved_spl_level < handler[irqno].level)
103d6cadcddSbsh 			s3c2xx0_setipl(handler[irqno].level);
104d6cadcddSbsh 
105d6cadcddSbsh 		/* clear pending bit */
106a99b5e08Sbsh 		icreg(INTCTL_SRCPND) = PENDING_CLEAR_MASK & (1 << irqno);
107675f6328Sbsh 
108675f6328Sbsh 		enable_interrupts(I32_bit); /* allow nested interrupts */
109675f6328Sbsh 
110d6cadcddSbsh 		(*handler[irqno].func) (
111d6cadcddSbsh 		    handler[irqno].cookie == 0
112d6cadcddSbsh 		    ? frame : handler[irqno].cookie);
113d6cadcddSbsh 
114675f6328Sbsh 		disable_interrupts(I32_bit);
115d6cadcddSbsh 
116d6cadcddSbsh 		/* restore spl to that was when this interrupt happen */
117d6cadcddSbsh 		s3c2xx0_setipl(saved_spl_level);
118675f6328Sbsh 	}
119675f6328Sbsh 
1200c0de807Smatt #ifdef __HAVE_FAST_SOFTINTS
121825088edSmatt 	cpu_dosoftints();
1220c0de807Smatt #endif
123d6cadcddSbsh }
124d6cadcddSbsh 
125a99b5e08Sbsh static const u_char s3c2800_ist[] = {
126a99b5e08Sbsh 	EXTINTR_LOW,		/* NONE */
127a99b5e08Sbsh 	EXTINTR_FALLING,	/* PULSE */
128a99b5e08Sbsh 	EXTINTR_FALLING,	/* EDGE */
129a99b5e08Sbsh 	EXTINTR_LOW,		/* LEVEL */
130a99b5e08Sbsh 	EXTINTR_HIGH,
131a99b5e08Sbsh 	EXTINTR_RISING,
132a99b5e08Sbsh 	EXTINTR_BOTH,
133a99b5e08Sbsh };
134d6cadcddSbsh 
135d6cadcddSbsh void *
s3c2800_intr_establish(int irqno,int level,int type,int (* func)(void *),void * cookie)136a99b5e08Sbsh s3c2800_intr_establish(int irqno, int level, int type,
137d6cadcddSbsh     int (* func) (void *), void *cookie)
138d6cadcddSbsh {
139d6cadcddSbsh 	int save;
140d6cadcddSbsh 
141a99b5e08Sbsh 	if (irqno < 0 || irqno >= ICU_LEN ||
142a99b5e08Sbsh 	    type < IST_NONE || IST_EDGE_BOTH < type)
143d6cadcddSbsh 		panic("intr_establish: bogus irq or type");
144d6cadcddSbsh 
145d6cadcddSbsh 	save = disable_interrupts(I32_bit);
146d6cadcddSbsh 
147d6cadcddSbsh 	handler[irqno].cookie = cookie;
148d6cadcddSbsh 	handler[irqno].func = func;
149d6cadcddSbsh 	handler[irqno].level = level;
150d6cadcddSbsh 
151d6cadcddSbsh 	s3c2xx0_update_intr_masks(irqno, level);
152d6cadcddSbsh 
153a99b5e08Sbsh 	if (irqno <= S3C2800_INT_EXT(7)) {
154a99b5e08Sbsh 		/*
155a99b5e08Sbsh 		 * Update external interrupt control
156a99b5e08Sbsh 		 */
157a99b5e08Sbsh 		uint32_t reg;
158a99b5e08Sbsh 		u_int 	trig;
159a99b5e08Sbsh 
160a99b5e08Sbsh 		trig = s3c2800_ist[type];
161a99b5e08Sbsh 
162a99b5e08Sbsh 		reg = bus_space_read_4(s3c2xx0_softc->sc_iot,
163a99b5e08Sbsh 				       s3c2xx0_softc->sc_gpio_ioh,
164a99b5e08Sbsh 				       GPIO_EXTINTR);
165a99b5e08Sbsh 
166a99b5e08Sbsh 		reg = reg & ~(0x0f << (4*irqno));
167a99b5e08Sbsh 		reg |= trig << (4*irqno);
168a99b5e08Sbsh 
169a99b5e08Sbsh 		bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
170a99b5e08Sbsh 				  GPIO_EXTINTR, reg);
171a99b5e08Sbsh 	}
172a99b5e08Sbsh 
173825088edSmatt 	s3c2xx0_setipl(curcpl());
174d6cadcddSbsh 
175d6cadcddSbsh 	restore_interrupts(save);
176d6cadcddSbsh 
177d6cadcddSbsh 	return (&handler[irqno]);
178d6cadcddSbsh }
179d6cadcddSbsh 
180d6cadcddSbsh 
181b80cc897Sbsh static void
init_interrupt_masks(void)182b80cc897Sbsh init_interrupt_masks(void)
183b80cc897Sbsh {
184825088edSmatt 	int i;
185b80cc897Sbsh 
186825088edSmatt 	for (i = 0; i < NIPL; i++)
187b80cc897Sbsh 		s3c2xx0_imask[i] = 0;
188b80cc897Sbsh }
189b80cc897Sbsh 
190d6cadcddSbsh void
s3c2800_intr_init(struct s3c2800_softc * sc)191d6cadcddSbsh s3c2800_intr_init(struct s3c2800_softc *sc)
192d6cadcddSbsh {
193d6cadcddSbsh 	intctl_base = (vaddr_t) bus_space_vaddr(sc->sc_sx.sc_iot,
194d6cadcddSbsh 	    sc->sc_sx.sc_intctl_ioh);
195d6cadcddSbsh 
196d6cadcddSbsh 	s3c2xx0_intr_mask_reg = (uint32_t *)(intctl_base + INTCTL_INTMSK);
197d6cadcddSbsh 
198d6cadcddSbsh 	/* clear all pending interrupt */
199d6cadcddSbsh 	icreg(INTCTL_SRCPND) = 0xffffffff;
200d6cadcddSbsh 
201b80cc897Sbsh 	init_interrupt_masks();
202b80cc897Sbsh 
203d6cadcddSbsh 	s3c2xx0_intr_init(handler, ICU_LEN);
204a99b5e08Sbsh 
205d6cadcddSbsh }
206