sync hh.org
[hh.org.git] / arch / ppc / syslib / ppc4xx_pic.c
blobee0da4b4b993c41f81750facfc7a091b6a056b3d
1 /*
2 * Interrupt controller driver for PowerPC 4xx-based processors.
4 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
5 * Copyright (c) 2004, 2005 Zultys Technologies
7 * Based on original code by
8 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
9 * Armin Custer <akuster@mvista.com>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
16 #include <linux/init.h>
17 #include <linux/sched.h>
18 #include <linux/signal.h>
19 #include <linux/stddef.h>
21 #include <asm/processor.h>
22 #include <asm/system.h>
23 #include <asm/irq.h>
24 #include <asm/ppc4xx_pic.h>
25 #include <asm/machdep.h>
27 /* See comment in include/arch-ppc/ppc4xx_pic.h
28 * for more info about these two variables
30 extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS]
31 __attribute__ ((weak));
32 extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak));
34 #define IRQ_MASK_UIC0(irq) (1 << (31 - (irq)))
35 #define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f)))
36 #define IRQ_MASK_UIC1(irq) IRQ_MASK_UICx(irq)
37 #define IRQ_MASK_UIC2(irq) IRQ_MASK_UICx(irq)
38 #define IRQ_MASK_UIC3(irq) IRQ_MASK_UICx(irq)
40 #define UIC_HANDLERS(n) \
41 static void ppc4xx_uic##n##_enable(unsigned int irq) \
42 { \
43 u32 mask = IRQ_MASK_UIC##n(irq); \
44 if (irq_desc[irq].status & IRQ_LEVEL) \
45 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
46 ppc_cached_irq_mask[n] |= mask; \
47 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
48 } \
50 static void ppc4xx_uic##n##_disable(unsigned int irq) \
51 { \
52 ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq); \
53 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
54 ACK_UIC##n##_PARENT \
55 } \
57 static void ppc4xx_uic##n##_ack(unsigned int irq) \
58 { \
59 u32 mask = IRQ_MASK_UIC##n(irq); \
60 ppc_cached_irq_mask[n] &= ~mask; \
61 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
62 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
63 ACK_UIC##n##_PARENT \
64 } \
66 static void ppc4xx_uic##n##_end(unsigned int irq) \
67 { \
68 unsigned int status = irq_desc[irq].status; \
69 u32 mask = IRQ_MASK_UIC##n(irq); \
70 if (status & IRQ_LEVEL) { \
71 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
72 ACK_UIC##n##_PARENT \
73 } \
74 if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { \
75 ppc_cached_irq_mask[n] |= mask; \
76 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
77 } \
80 #define DECLARE_UIC(n) \
81 { \
82 .typename = "UIC"#n, \
83 .enable = ppc4xx_uic##n##_enable, \
84 .disable = ppc4xx_uic##n##_disable, \
85 .ack = ppc4xx_uic##n##_ack, \
86 .end = ppc4xx_uic##n##_end, \
87 } \
89 #if NR_UICS == 4
90 #define ACK_UIC0_PARENT
91 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
92 #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC2NC);
93 #define ACK_UIC3_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC3NC);
94 UIC_HANDLERS(0);
95 UIC_HANDLERS(1);
96 UIC_HANDLERS(2);
97 UIC_HANDLERS(3);
99 static int ppc4xx_pic_get_irq(void)
101 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
102 if (uic0 & UIC0_UIC1NC)
103 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
104 else if (uic0 & UIC0_UIC2NC)
105 return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
106 else if (uic0 & UIC0_UIC3NC)
107 return 128 - ffs(mfdcr(DCRN_UIC_MSR(UIC3)));
108 else
109 return uic0 ? 32 - ffs(uic0) : -1;
112 static void __init ppc4xx_pic_impl_init(void)
114 /* Enable cascade interrupts in UIC0 */
115 ppc_cached_irq_mask[0] |= UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC;
116 mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC);
117 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
120 #elif NR_UICS == 3
121 #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
122 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
123 #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
124 UIC_HANDLERS(0);
125 UIC_HANDLERS(1);
126 UIC_HANDLERS(2);
128 static int ppc4xx_pic_get_irq(void)
130 u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
131 if (uicb & UICB_UIC0NC)
132 return 32 - ffs(mfdcr(DCRN_UIC_MSR(UIC0)));
133 else if (uicb & UICB_UIC1NC)
134 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
135 else if (uicb & UICB_UIC2NC)
136 return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
137 else
138 return -1;
141 static void __init ppc4xx_pic_impl_init(void)
143 #if defined(CONFIG_440GX)
144 /* Disable 440GP compatibility mode if it was enabled in firmware */
145 SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~DCRN_SDR_MFR_PCM);
146 #endif
147 /* Configure Base UIC */
148 mtdcr(DCRN_UIC_CR(UICB), 0);
149 mtdcr(DCRN_UIC_TR(UICB), 0);
150 mtdcr(DCRN_UIC_PR(UICB), 0xffffffff);
151 mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
152 mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
155 #elif NR_UICS == 2
156 #define ACK_UIC0_PARENT
157 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
158 UIC_HANDLERS(0);
159 UIC_HANDLERS(1);
161 static int ppc4xx_pic_get_irq(void)
163 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
164 if (uic0 & UIC0_UIC1NC)
165 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
166 else
167 return uic0 ? 32 - ffs(uic0) : -1;
170 static void __init ppc4xx_pic_impl_init(void)
172 /* Enable cascade interrupt in UIC0 */
173 ppc_cached_irq_mask[0] |= UIC0_UIC1NC;
174 mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
175 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
178 #elif NR_UICS == 1
179 #define ACK_UIC0_PARENT
180 UIC_HANDLERS(0);
182 static int ppc4xx_pic_get_irq(void)
184 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
185 return uic0 ? 32 - ffs(uic0) : -1;
188 static inline void ppc4xx_pic_impl_init(void)
191 #endif
193 static struct ppc4xx_uic_impl {
194 struct hw_interrupt_type decl;
195 int base; /* Base DCR number */
196 } __uic[] = {
197 { .decl = DECLARE_UIC(0), .base = UIC0 },
198 #if NR_UICS > 1
199 { .decl = DECLARE_UIC(1), .base = UIC1 },
200 #if NR_UICS > 2
201 { .decl = DECLARE_UIC(2), .base = UIC2 },
202 #if NR_UICS > 3
203 { .decl = DECLARE_UIC(3), .base = UIC3 },
204 #endif
205 #endif
206 #endif
209 static inline int is_level_sensitive(int irq)
211 u32 tr = mfdcr(DCRN_UIC_TR(__uic[irq >> 5].base));
212 return (tr & IRQ_MASK_UICx(irq)) == 0;
215 void __init ppc4xx_pic_init(void)
217 int i;
218 unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg;
220 for (i = 0; i < NR_UICS; ++i) {
221 int base = __uic[i].base;
223 /* Disable everything by default */
224 ppc_cached_irq_mask[i] = 0;
225 mtdcr(DCRN_UIC_ER(base), 0);
227 /* We don't use critical interrupts */
228 mtdcr(DCRN_UIC_CR(base), 0);
230 /* Configure polarity and triggering */
231 if (ppc4xx_core_uic_cfg) {
232 struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i;
233 u32 mask = p->ext_irq_mask;
234 u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask;
235 u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask;
237 /* "Fixed" interrupts (on-chip devices) */
238 pr |= p->polarity & ~mask;
239 tr |= p->triggering & ~mask;
241 /* Merge external IRQs settings if board port
242 * provided them
244 if (eirqs && mask) {
245 pr &= ~mask;
246 tr &= ~mask;
247 while (mask) {
248 /* Extract current external IRQ mask */
249 u32 eirq_mask = 1 << __ilog2(mask);
251 if (!(*eirqs & IRQ_SENSE_LEVEL))
252 tr |= eirq_mask;
254 if (*eirqs & IRQ_POLARITY_POSITIVE)
255 pr |= eirq_mask;
257 mask &= ~eirq_mask;
258 ++eirqs;
261 mtdcr(DCRN_UIC_PR(base), pr);
262 mtdcr(DCRN_UIC_TR(base), tr);
265 /* ACK any pending interrupts to prevent false
266 * triggering after first enable
268 mtdcr(DCRN_UIC_SR(base), 0xffffffff);
271 /* Perform optional implementation specific setup
272 * (e.g. enable cascade interrupts for multi-UIC configurations)
274 ppc4xx_pic_impl_init();
276 /* Attach low-level handlers */
277 for (i = 0; i < (NR_UICS << 5); ++i) {
278 irq_desc[i].chip = &__uic[i >> 5].decl;
279 if (is_level_sensitive(i))
280 irq_desc[i].status |= IRQ_LEVEL;
283 ppc_md.get_irq = ppc4xx_pic_get_irq;