Annotation of sys/arch/arm/s3c2xx0/s3c2800_intr.c, Revision 1.1.1.1
1.1 nbrk 1: /* $NetBSD: s3c2800_intr.c,v 1.9 2005/12/24 20:06:52 perry Exp $ */
2:
3: /*
4: * Copyright (c) 2002 Fujitsu Component Limited
5: * Copyright (c) 2002 Genetec Corporation
6: * All rights reserved.
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: * 3. Neither the name of The Fujitsu Component Limited nor the name of
17: * Genetec corporation may not be used to endorse or promote products
18: * derived from this software without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
21: * CORPORATION ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24: * DISCLAIMED. IN NO EVENT SHALL FUJITSU COMPONENT LIMITED OR GENETEC
25: * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
35: /*
36: * IRQ handler for Samsung S3C2800 processor.
37: * It has integrated interrupt controller.
38: */
39:
40: #include <sys/cdefs.h>
41: __KERNEL_RCSID(0, "$NetBSD: s3c2800_intr.c,v 1.9 2005/12/24 20:06:52 perry Exp $");
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/malloc.h>
46: #include <uvm/uvm_extern.h>
47: #include <machine/bus.h>
48: #include <machine/intr.h>
49: #include <arm/cpufunc.h>
50:
51: #include <arm/s3c2xx0/s3c2800reg.h>
52: #include <arm/s3c2xx0/s3c2800var.h>
53:
54: /*
55: * interrupt dispatch table.
56: */
57:
58: struct s3c2xx0_intr_dispatch handler[ICU_LEN];
59:
60: volatile int softint_pending;
61:
62: volatile int current_spl_level;
63: volatile int intr_mask; /* XXX: does this need to be volatile? */
64: volatile int global_intr_mask = 0; /* mask some interrupts at all spl level */
65:
66: /* interrupt masks for each level */
67: int s3c2xx0_imask[NIPL];
68: int s3c2xx0_ilevel[ICU_LEN];
69:
70: vaddr_t intctl_base; /* interrupt controller registers */
71: #define icreg(offset) \
72: (*(volatile uint32_t *)(intctl_base+(offset)))
73:
74: /*
75: * Map a software interrupt queue to an interrupt priority level.
76: */
77: static const int si_to_ipl[SI_NQUEUES] = {
78: IPL_SOFT, /* SI_SOFT */
79: IPL_SOFTCLOCK, /* SI_SOFTCLOCK */
80: IPL_SOFTNET, /* SI_SOFTNET */
81: IPL_SOFTSERIAL, /* SI_SOFTSERIAL */
82: };
83:
84: /*
85: * Clearing interrupt pending bits affects some built-in
86: * peripherals. For example, IIC starts transmitting next data when
87: * its interrupt pending bit is cleared.
88: * We need to leave those bits to peripheral handlers.
89: */
90: #define PENDING_CLEAR_MASK (~((1<<S3C2800_INT_IIC0)|(1<<S3C2800_INT_IIC1)))
91:
92: /*
93: * called from irq_entry.
94: */
95: void s3c2800_irq_handler(struct clockframe *);
96: void
97: s3c2800_irq_handler(struct clockframe *frame)
98: {
99: uint32_t irqbits;
100: int irqno;
101: int saved_spl_level;
102:
103: saved_spl_level = current_spl_level;
104:
105: while ((irqbits = icreg(INTCTL_IRQPND) & ICU_INT_HWMASK) != 0) {
106:
107: for (irqno = ICU_LEN-1; irqno >= 0; --irqno)
108: if (irqbits & (1<<irqno))
109: break;
110:
111: if (irqno < 0)
112: break;
113:
114: /* raise spl to stop interrupts of lower priorities */
115: if (saved_spl_level < handler[irqno].level)
116: s3c2xx0_setipl(handler[irqno].level);
117:
118: /* clear pending bit */
119: icreg(INTCTL_SRCPND) = PENDING_CLEAR_MASK & (1 << irqno);
120:
121: enable_interrupts(I32_bit); /* allow nested interrupts */
122:
123: (*handler[irqno].func) (
124: handler[irqno].cookie == 0
125: ? frame : handler[irqno].cookie);
126:
127: disable_interrupts(I32_bit);
128:
129: /* restore spl to that was when this interrupt happen */
130: s3c2xx0_setipl(saved_spl_level);
131: }
132:
133:
134: if (softint_pending & intr_mask)
135: s3c2xx0_do_pending(1);
136:
137: }
138:
139: static const u_char s3c2800_ist[] = {
140: EXTINTR_LOW, /* NONE */
141: EXTINTR_FALLING, /* PULSE */
142: EXTINTR_FALLING, /* EDGE */
143: EXTINTR_LOW, /* LEVEL */
144: EXTINTR_HIGH,
145: EXTINTR_RISING,
146: EXTINTR_BOTH,
147: };
148:
149: void *
150: s3c2800_intr_establish(int irqno, int level, int type,
151: int (* func) (void *), void *cookie)
152: {
153: int save;
154:
155: if (irqno < 0 || irqno >= ICU_LEN ||
156: type < IST_NONE || IST_EDGE_BOTH < type)
157: panic("intr_establish: bogus irq or type");
158:
159: save = disable_interrupts(I32_bit);
160:
161: handler[irqno].cookie = cookie;
162: handler[irqno].func = func;
163: handler[irqno].level = level;
164:
165: s3c2xx0_update_intr_masks(irqno, level);
166:
167: if (irqno <= S3C2800_INT_EXT(7)) {
168: /*
169: * Update external interrupt control
170: */
171: uint32_t reg;
172: u_int trig;
173:
174: trig = s3c2800_ist[type];
175:
176: reg = bus_space_read_4(s3c2xx0_softc->sc_iot,
177: s3c2xx0_softc->sc_gpio_ioh,
178: GPIO_EXTINTR);
179:
180: reg = reg & ~(0x0f << (4*irqno));
181: reg |= trig << (4*irqno);
182:
183: bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
184: GPIO_EXTINTR, reg);
185: }
186:
187: s3c2xx0_setipl(current_spl_level);
188:
189: restore_interrupts(save);
190:
191: return (&handler[irqno]);
192: }
193:
194:
195: static void
196: init_interrupt_masks(void)
197: {
198: int i;
199:
200: s3c2xx0_imask[IPL_NONE] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
201: SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK) |
202: SI_TO_IRQBIT(SI_SOFT);
203:
204: s3c2xx0_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
205: SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK);
206:
207: /*
208: * splsoftclock() is the only interface that users of the
209: * generic software interrupt facility have to block their
210: * soft intrs, so splsoftclock() must also block IPL_SOFT.
211: */
212: s3c2xx0_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
213: SI_TO_IRQBIT(SI_SOFTNET);
214:
215: /*
216: * splsoftnet() must also block splsoftclock(), since we don't
217: * want timer-driven network events to occur while we're
218: * processing incoming packets.
219: */
220: s3c2xx0_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTSERIAL);
221:
222: for (i = IPL_BIO; i < IPL_SOFTSERIAL; ++i)
223: s3c2xx0_imask[i] = SI_TO_IRQBIT(SI_SOFTSERIAL);
224: for (; i < NIPL; ++i)
225: s3c2xx0_imask[i] = 0;
226: }
227:
228: void
229: s3c2800_intr_init(struct s3c2800_softc *sc)
230: {
231: intctl_base = (vaddr_t) bus_space_vaddr(sc->sc_sx.sc_iot,
232: sc->sc_sx.sc_intctl_ioh);
233:
234: s3c2xx0_intr_mask_reg = (uint32_t *)(intctl_base + INTCTL_INTMSK);
235:
236: /* clear all pending interrupt */
237: icreg(INTCTL_SRCPND) = 0xffffffff;
238:
239: init_interrupt_masks();
240:
241: s3c2xx0_intr_init(handler, ICU_LEN);
242:
243: }
CVSweb