vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc / syslib / ppc4xx_pic.c
1 /*
2  * arch/ppc/syslib/ppc4xx_pic.c
3  *
4  * Interrupt controller driver for PowerPC 4xx-based processors.
5  *
6  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7  * Copyright (c) 2004 Zultys Technologies
8  *
9  * Based on original code by
10  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
11  *    Armin Custer <akuster@mvista.com>
12  *
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.
17 */
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>
23
24 #include <asm/processor.h>
25 #include <asm/system.h>
26 #include <asm/irq.h>
27 #include <asm/ppc4xx_pic.h>
28
29 /* See comment in include/arch-ppc/ppc4xx_pic.h
30  * for more info about these two variables
31  */
32 extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS] __attribute__((weak));
33 extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__((weak));
34
35 #define IRQ_MASK_UIC0(irq)              (1 << (31 - (irq)))
36 #define IRQ_MASK_UICx(irq)              (1 << (31 - ((irq) & 0x1f)))
37 #define IRQ_MASK_UIC1(irq)              IRQ_MASK_UICx(irq)
38 #define IRQ_MASK_UIC2(irq)              IRQ_MASK_UICx(irq)
39
40 #define UIC_HANDLERS(n)                                                 \
41 static void ppc4xx_uic##n##_enable(unsigned int irq)                    \
42 {                                                                       \
43         ppc_cached_irq_mask[n] |= IRQ_MASK_UIC##n(irq);                 \
44         mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);             \
45 }                                                                       \
46                                                                         \
47 static void ppc4xx_uic##n##_disable(unsigned int irq)                   \
48 {                                                                       \
49         ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq);                \
50         mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);             \
51 }                                                                       \
52                                                                         \
53 static void ppc4xx_uic##n##_ack(unsigned int irq)                       \
54 {                                                                       \
55         u32 mask = IRQ_MASK_UIC##n(irq);                                \
56         ppc_cached_irq_mask[n] &= ~mask;                                \
57         mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);             \
58         mtdcr(DCRN_UIC_SR(UIC##n), mask);                               \
59         ACK_UIC##n##_PARENT                                             \
60 }                                                                       \
61                                                                         \
62 static void ppc4xx_uic##n##_end(unsigned int irq)                       \
63 {                                                                       \
64         unsigned int status = irq_desc[irq].status;                     \
65         u32 mask = IRQ_MASK_UIC##n(irq);                                \
66         if (status & IRQ_LEVEL){                                        \
67                 mtdcr(DCRN_UIC_SR(UIC##n), mask);                       \
68                 ACK_UIC##n##_PARENT                                     \
69         }                                                               \
70         if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))){               \
71                 ppc_cached_irq_mask[n] |= mask;                         \
72                 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);     \
73         }                                                               \
74 }
75
76 #define DECLARE_UIC(n)                                                  \
77 {                                                                       \
78         .typename       = "UIC"#n,                                      \
79         .enable         = ppc4xx_uic##n##_enable,                       \
80         .disable        = ppc4xx_uic##n##_disable,                      \
81         .ack            = ppc4xx_uic##n##_ack,                          \
82         .end            = ppc4xx_uic##n##_end,                          \
83 }                                                                       \
84
85 #if NR_UICS == 3
86 #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
87 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
88 #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
89 UIC_HANDLERS(0); UIC_HANDLERS(1); UIC_HANDLERS(2);
90
91 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
92 {
93         u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
94         if (uicb & UICB_UIC0NC)
95                 return 32 - ffs(mfdcr(DCRN_UIC_MSR(UIC0)));
96         else if (uicb & UICB_UIC1NC)
97                 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
98         else if (uicb & UICB_UIC2NC)
99                 return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
100         else
101                 return -1;
102 }
103
104 static void __init ppc4xx_pic_impl_init(void)
105 {
106         /* Configure Base UIC */
107         mtdcr(DCRN_UIC_CR(UICB), 0);
108         mtdcr(DCRN_UIC_TR(UICB), 0);
109         mtdcr(DCRN_UIC_PR(UICB), 0xffffffff);
110         mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
111         mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
112 }
113
114 #elif NR_UICS == 2
115 #define ACK_UIC0_PARENT
116 #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
117 UIC_HANDLERS(0); UIC_HANDLERS(1);
118
119 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
120 {
121         u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
122         if (uic0 & UIC0_UIC1NC)
123                 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
124         else
125                 return uic0 ? 32 - ffs(uic0) : -1;
126 }
127
128 static void __init ppc4xx_pic_impl_init(void)
129 {
130         /* Enable cascade interrupt in UIC0 */
131         ppc_cached_irq_mask[0] |= UIC0_UIC1NC;
132         mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
133         mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
134 }
135
136 #elif NR_UICS == 1
137 #define ACK_UIC0_PARENT
138 UIC_HANDLERS(0);
139
140 static int ppc4xx_pic_get_irq(struct pt_regs *regs)
141 {
142         u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
143         return uic0 ? 32 - ffs(uic0) : -1;
144 }
145
146 static inline void ppc4xx_pic_impl_init(void){}
147 #endif
148
149 static struct ppc4xx_uic_impl {
150         struct hw_interrupt_type decl;
151         int                      base;          /* Base DCR number */
152 } __uic[] = {
153     { .decl = DECLARE_UIC(0), .base = UIC0 },
154 #if NR_UICS > 1
155     { .decl = DECLARE_UIC(1), .base = UIC1 },
156 #if NR_UICS > 2
157     { .decl = DECLARE_UIC(2), .base = UIC2 },
158 #endif
159 #endif
160 };
161
162 static inline int is_level_sensitive(int irq)
163 {
164         u32 tr = mfdcr(DCRN_UIC_TR(__uic[irq >> 5].base));
165         return (tr & IRQ_MASK_UICx(irq)) == 0;
166 }
167
168 void __init ppc4xx_pic_init(void)
169 {
170         int i;
171         unsigned char* eirqs = ppc4xx_uic_ext_irq_cfg;
172
173         for (i = 0; i < NR_UICS; ++i){
174                 int base = __uic[i].base;
175
176                 /* Disable everything by default */
177                 ppc_cached_irq_mask[i] = 0;
178                 mtdcr(DCRN_UIC_ER(base), 0);
179
180                 /* We don't use critical interrupts */
181                 mtdcr(DCRN_UIC_CR(base), 0);
182
183                 /* Configure polarity and triggering */
184                 if (ppc4xx_core_uic_cfg){
185                         struct ppc4xx_uic_settings* p = ppc4xx_core_uic_cfg + i;
186                         u32 mask = p->ext_irq_mask;
187                         u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask;
188                         u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask;
189
190                         /* "Fixed" interrupts (on-chip devices) */
191                         pr |= p->polarity   & ~mask;
192                         tr |= p->triggering & ~mask;
193
194                         /* Merge external IRQs settings if board port
195                          * provided them
196                          */
197                         if (eirqs && mask){
198                                 pr &= ~mask;
199                                 tr &= ~mask;
200                                 while (mask){
201                                         /* Extract current external IRQ mask */
202                                         u32 eirq_mask = 1 << __ilog2(mask);
203
204                                         if (!(*eirqs & IRQ_SENSE_LEVEL))
205                                                 tr |= eirq_mask;
206
207                                         if (*eirqs & IRQ_POLARITY_POSITIVE)
208                                                 pr |= eirq_mask;
209
210                                         mask &= ~eirq_mask;
211                                         ++eirqs;
212                                 }
213                         }
214                         mtdcr(DCRN_UIC_PR(base), pr);
215                         mtdcr(DCRN_UIC_TR(base), tr);
216                 }
217
218                 /* ACK any pending interrupts to prevent false
219                  * triggering after first enable
220                  */
221                 mtdcr(DCRN_UIC_SR(base), 0xffffffff);
222         }
223
224         /* Perform optional implementation specific setup
225          * (e.g. enable cascade interrupts for multi-UIC configurations)
226          */
227         ppc4xx_pic_impl_init();
228
229         /* Attach low-level handlers */
230         for (i = 0; i < (NR_UICS << 5); ++i){
231                 irq_desc[i].handler = &__uic[i >> 5].decl;
232                 if (is_level_sensitive(i))
233                         irq_desc[i].status |= IRQ_LEVEL;
234         }
235
236         ppc_md.get_irq = ppc4xx_pic_get_irq;
237 }