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