1 /* $NetBSD: pxa2x0_intr.c,v 1.15 2008/11/07 16:14:37 rafal Exp $ */
4 * Copyright (c) 2002 Genetec Corporation. All rights reserved.
5 * Written by Hiroyuki Bessho for Genetec Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project by
18 * Genetec Corporation.
19 * 4. The name of Genetec Corporation may not be used to endorse or
20 * promote products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
37 * IRQ handler for the Intel PXA2X0 processor.
38 * It has integrated interrupt controller.
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: pxa2x0_intr.c,v 1.15 2008/11/07 16:14:37 rafal Exp $");
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/malloc.h>
48 #include <machine/bus.h>
49 #include <machine/intr.h>
50 #include <machine/lock.h>
52 #include <arm/xscale/pxa2x0cpu.h>
53 #include <arm/xscale/pxa2x0reg.h>
54 #include <arm/xscale/pxa2x0var.h>
55 #include <arm/xscale/pxa2x0_intr.h>
56 #include <arm/sa11x0/sa11x0_var.h>
61 static int pxaintc_match(struct device
*, struct cfdata
*, void *);
62 static void pxaintc_attach(struct device
*, struct device
*, void *);
64 CFATTACH_DECL(pxaintc
, sizeof(struct device
),
65 pxaintc_match
, pxaintc_attach
, NULL
, NULL
);
67 static int pxaintc_attached
;
69 static int stray_interrupt(void *);
70 static void init_interrupt_masks(void);
73 * interrupt dispatch table.
75 #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
77 TAILQ_ENTRY(intrhand
) ih_list
; /* link on intrq list */
78 int (*ih_func
)(void *); /* handler */
79 void *ih_arg
; /* arg for handler */
83 static struct intrhandler
{
84 #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
85 TAILQ_HEAD(,intrhand
) list
;
87 pxa2x0_irq_handler_t func
;
89 void *cookie
; /* NULL for stackframe */
90 /* struct evbnt ev; */
93 volatile int softint_pending
;
94 volatile int intr_mask
;
95 /* interrupt masks for each level */
96 int pxa2x0_imask
[NIPL
];
97 static int extirq_level
[ICU_LEN
];
101 pxaintc_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
103 struct pxaip_attach_args
*pxa
= aux
;
105 if (pxaintc_attached
|| pxa
->pxa_addr
!= PXA2X0_INTCTL_BASE
)
112 pxaintc_attach(struct device
*parent
, struct device
*self
, void *args
)
116 pxaintc_attached
= 1;
118 aprint_normal(": Interrupt Controller\n");
120 #define SAIPIC_ICCR 0x14
122 write_icu(SAIPIC_ICCR
, 1);
123 write_icu(SAIPIC_MR
, 0);
125 for(i
= 0; i
< sizeof handler
/ sizeof handler
[0]; ++i
){
126 handler
[i
].func
= stray_interrupt
;
127 handler
[i
].cookie
= (void *)(intptr_t) i
;
128 extirq_level
[i
] = IPL_SERIAL
;
131 init_interrupt_masks();
133 _splraise(IPL_SERIAL
);
134 enable_interrupts(I32_bit
);
138 * Invoked very early on from the board-specific initarm(), in order to
139 * inform us the virtual address of the interrupt controller's registers.
142 pxa2x0_intr_bootstrap(vaddr_t addr
)
152 if (curcpu()->ci_cpl
< ipl
)
157 * called from irq_entry.
160 pxa2x0_irq_handler(void *arg
)
162 struct clockframe
*frame
= arg
;
167 saved_spl_level
= curcpu()->ci_cpl
;
169 /* get pending IRQs */
170 irqbits
= read_icu(SAIPIC_IP
);
172 while ((irqno
= find_first_bit(irqbits
)) >= 0) {
173 /* XXX: Shuould we handle IRQs in priority order? */
175 /* raise spl to stop interrupts of lower priorities */
176 if (saved_spl_level
< extirq_level
[irqno
])
177 pxa2x0_setipl(extirq_level
[irqno
]);
180 /* Enable interrupt */
182 #ifndef MULTIPLE_HANDLERS_ON_ONE_IRQ
183 (* handler
[irqno
].func
)(
184 handler
[irqno
].cookie
== 0
185 ? frame
: handler
[irqno
].cookie
);
187 /* process all handlers for this interrupt.
192 /* Disable interrupt */
195 irqbits
&= ~(1<<irqno
);
198 /* restore spl to that was when this interrupt happen */
199 pxa2x0_setipl(saved_spl_level
);
201 #ifdef __HAVE_FAST_SOFTINTS
207 stray_interrupt(void *cookie
)
209 int irqno
= (int)cookie
;
210 int irqmin
= CPU_IS_PXA250
? PXA250_IRQ_MIN
: PXA270_IRQ_MIN
;
212 printf("stray interrupt %d\n", irqno
);
214 if (irqmin
<= irqno
&& irqno
< ICU_LEN
){
215 int save
= disable_interrupts(I32_bit
);
217 read_icu(SAIPIC_MR
) & ~(1U<<irqno
));
218 restore_interrupts(save
);
227 * Interrupt Mask Handling
231 pxa2x0_update_intr_masks(int irqno
, int level
)
233 int mask
= 1U<<irqno
;
234 int psw
= disable_interrupts(I32_bit
);
237 for(i
= 0; i
< level
; ++i
)
238 pxa2x0_imask
[i
] |= mask
; /* Enable interrupt at lower level */
240 for( ; i
< NIPL
-1; ++i
)
241 pxa2x0_imask
[i
] &= ~mask
; /* Disable itnerrupt at upper level */
244 * Enforce a hierarchy that gives "slow" device (or devices with
245 * limited input buffer space/"real-time" requirements) a better
246 * chance at not dropping data.
248 pxa2x0_imask
[IPL_SOFTBIO
] &= pxa2x0_imask
[IPL_SOFTCLOCK
];
249 pxa2x0_imask
[IPL_SOFTNET
] &= pxa2x0_imask
[IPL_SOFTBIO
];
250 pxa2x0_imask
[IPL_SOFTSERIAL
] &= pxa2x0_imask
[IPL_SOFTNET
];
251 pxa2x0_imask
[IPL_VM
] &= pxa2x0_imask
[IPL_SOFTSERIAL
];
252 pxa2x0_imask
[IPL_SCHED
] &= pxa2x0_imask
[IPL_VM
];
253 pxa2x0_imask
[IPL_HIGH
] &= pxa2x0_imask
[IPL_SCHED
];
255 write_icu(SAIPIC_MR
, pxa2x0_imask
[curcpu()->ci_cpl
]);
257 restore_interrupts(psw
);
262 init_interrupt_masks(void)
266 * disable all interrups until handlers are installed.
268 memset(pxa2x0_imask
, 0, sizeof(pxa2x0_imask
));
283 return pxa2x0_splraise(ipl
);
290 return pxa2x0_spllower(ipl
);
294 pxa2x0_intr_establish(int irqno
, int level
,
295 int (*func
)(void *), void *cookie
)
298 int irqmin
= CPU_IS_PXA250
? PXA250_IRQ_MIN
: PXA270_IRQ_MIN
;
300 if (irqno
< irqmin
|| irqno
>= ICU_LEN
)
301 panic("intr_establish: bogus irq number %d", irqno
);
303 psw
= disable_interrupts(I32_bit
);
305 handler
[irqno
].cookie
= cookie
;
306 handler
[irqno
].func
= func
;
307 extirq_level
[irqno
] = level
;
308 pxa2x0_update_intr_masks(irqno
, level
);
310 intr_mask
= pxa2x0_imask
[curcpu()->ci_cpl
];
312 restore_interrupts(psw
);
314 return (&handler
[irqno
]);
318 pxa2x0_intr_disestablish(void *cookie
)
320 struct intrhandler
*lhandler
= cookie
, *ih
;
321 int irqmin
= CPU_IS_PXA250
? PXA250_IRQ_MIN
: PXA270_IRQ_MIN
;
322 int irqno
= lhandler
- handler
;
325 if (irqno
< irqmin
|| irqno
>= ICU_LEN
)
326 panic("intr_disestablish: bogus irq number %d", irqno
);
328 psw
= disable_interrupts(I32_bit
);
330 ih
= &handler
[irqno
];
331 ih
->func
= stray_interrupt
;
332 ih
->cookie
= (void *)(intptr_t)irqno
;
333 extirq_level
[irqno
] = IPL_SERIAL
;
334 pxa2x0_update_intr_masks(irqno
, IPL_SERIAL
);
336 restore_interrupts(psw
);
340 * Glue for drivers of sa11x0 compatible integrated logics.
343 sa11x0_intr_establish(sa11x0_chipset_tag_t ic
, int irq
, int type
, int level
,
344 int (*ih_fun
)(void *), void *ih_arg
)
347 return pxa2x0_intr_establish(irq
, level
, ih_fun
, ih_arg
);