2 * arch/ppc/syslib/ppc4xx_pic.c
4 * Interrupt controller driver for PowerPC 4xx-based processors.
6 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7 * Copyright (c) 2004, 2005 Zultys Technologies
9 * Based on original code by
10 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
11 * Armin Custer <akuster@mvista.com>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
18 #include <linux/config.h>
19 #include <linux/init.h>
20 #include <linux/sched.h>
21 #include <linux/signal.h>
22 #include <linux/stddef.h>
24 #include <asm/processor.h>
25 #include <asm/system.h>
27 #include <asm/ppc4xx_pic.h>
28 #include <asm/machdep.h>
30 /* See comment in include/arch-ppc/ppc4xx_pic.h
31 * for more info about these two variables
33 extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS]
34 __attribute__ ((weak));
35 extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak));
37 #define IRQ_MASK_UIC0(irq) (1 << (31 - (irq)))
38 #define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f)))
39 #define IRQ_MASK_UIC1(irq) IRQ_MASK_UICx(irq)
40 #define IRQ_MASK_UIC2(irq) IRQ_MASK_UICx(irq)
42 #define UIC_HANDLERS(n) \
43 static void ppc4xx_uic##n##_enable(unsigned int irq) \
45 u32 mask = IRQ_MASK_UIC##n(irq); \
46 if (irq_desc[irq].status & IRQ_LEVEL) \
47 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
48 ppc_cached_irq_mask[n] |= mask; \
49 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
52 static void ppc4xx_uic##n##_disable(unsigned int irq) \
54 ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq); \
55 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
59 static void ppc4xx_uic##n##_ack(unsigned int irq) \
61 u32 mask = IRQ_MASK_UIC##n(irq); \
62 ppc_cached_irq_mask[n] &= ~mask; \
63 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
64 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
68 static void ppc4xx_uic##n##_end(unsigned int irq) \
70 unsigned int status = irq_desc[irq].status; \
71 u32 mask = IRQ_MASK_UIC##n(irq); \
72 if (status & IRQ_LEVEL) { \
73 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
76 if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { \
77 ppc_cached_irq_mask[n] |= mask; \
78 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
82 #define DECLARE_UIC(n) \
84 .typename = "UIC"#n, \
85 .enable = ppc4xx_uic##n##_enable, \
86 .disable = ppc4xx_uic##n##_disable, \
87 .ack = ppc4xx_uic##n##_ack, \
88 .end = ppc4xx_uic##n##_end, \
92 #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
93 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
94 #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
99 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
101 u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
102 if (uicb & UICB_UIC0NC)
103 return 32 - ffs(mfdcr(DCRN_UIC_MSR(UIC0)));
104 else if (uicb & UICB_UIC1NC)
105 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
106 else if (uicb & UICB_UIC2NC)
107 return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
112 static void __init ppc4xx_pic_impl_init(void)
114 #if defined(CONFIG_440GX)
115 /* Disable 440GP compatibility mode if it was enabled in firmware */
116 SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~DCRN_SDR_MFR_PCM);
118 /* Configure Base UIC */
119 mtdcr(DCRN_UIC_CR(UICB), 0);
120 mtdcr(DCRN_UIC_TR(UICB), 0);
121 mtdcr(DCRN_UIC_PR(UICB), 0xffffffff);
122 mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
123 mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
127 #define ACK_UIC0_PARENT
128 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
132 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
134 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
135 if (uic0 & UIC0_UIC1NC)
136 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
138 return uic0 ? 32 - ffs(uic0) : -1;
141 static void __init ppc4xx_pic_impl_init(void)
143 /* Enable cascade interrupt in UIC0 */
144 ppc_cached_irq_mask[0] |= UIC0_UIC1NC;
145 mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
146 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
150 #define ACK_UIC0_PARENT
153 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
155 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
156 return uic0 ? 32 - ffs(uic0) : -1;
159 static inline void ppc4xx_pic_impl_init(void)
164 static struct ppc4xx_uic_impl {
165 struct hw_interrupt_type decl;
166 int base; /* Base DCR number */
168 { .decl = DECLARE_UIC(0), .base = UIC0 },
170 { .decl = DECLARE_UIC(1), .base = UIC1 },
172 { .decl = DECLARE_UIC(2), .base = UIC2 },
177 static inline int is_level_sensitive(int irq)
179 u32 tr = mfdcr(DCRN_UIC_TR(__uic[irq >> 5].base));
180 return (tr & IRQ_MASK_UICx(irq)) == 0;
183 void __init ppc4xx_pic_init(void)
186 unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg;
188 for (i = 0; i < NR_UICS; ++i) {
189 int base = __uic[i].base;
191 /* Disable everything by default */
192 ppc_cached_irq_mask[i] = 0;
193 mtdcr(DCRN_UIC_ER(base), 0);
195 /* We don't use critical interrupts */
196 mtdcr(DCRN_UIC_CR(base), 0);
198 /* Configure polarity and triggering */
199 if (ppc4xx_core_uic_cfg) {
200 struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i;
201 u32 mask = p->ext_irq_mask;
202 u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask;
203 u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask;
205 /* "Fixed" interrupts (on-chip devices) */
206 pr |= p->polarity & ~mask;
207 tr |= p->triggering & ~mask;
209 /* Merge external IRQs settings if board port
216 /* Extract current external IRQ mask */
217 u32 eirq_mask = 1 << __ilog2(mask);
219 if (!(*eirqs & IRQ_SENSE_LEVEL))
222 if (*eirqs & IRQ_POLARITY_POSITIVE)
229 mtdcr(DCRN_UIC_PR(base), pr);
230 mtdcr(DCRN_UIC_TR(base), tr);
233 /* ACK any pending interrupts to prevent false
234 * triggering after first enable
236 mtdcr(DCRN_UIC_SR(base), 0xffffffff);
239 /* Perform optional implementation specific setup
240 * (e.g. enable cascade interrupts for multi-UIC configurations)
242 ppc4xx_pic_impl_init();
244 /* Attach low-level handlers */
245 for (i = 0; i < (NR_UICS << 5); ++i) {
246 irq_desc[i].handler = &__uic[i >> 5].decl;
247 if (is_level_sensitive(i))
248 irq_desc[i].status |= IRQ_LEVEL;
251 ppc_md.get_irq = ppc4xx_pic_get_irq;