diff options
-rw-r--r-- | arch/powerpc/include/asm/mpc52xx.h | 19 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200_pm.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pic.c | 235 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pic.h | 53 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pm.c | 3 |
5 files changed, 189 insertions, 122 deletions
diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h index 81ef10b6b672..81a23932a160 100644 --- a/arch/powerpc/include/asm/mpc52xx.h +++ b/arch/powerpc/include/asm/mpc52xx.h | |||
@@ -239,6 +239,25 @@ struct mpc52xx_cdm { | |||
239 | u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ | 239 | u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ |
240 | }; | 240 | }; |
241 | 241 | ||
242 | /* Interrupt controller Register set */ | ||
243 | struct mpc52xx_intr { | ||
244 | u32 per_mask; /* INTR + 0x00 */ | ||
245 | u32 per_pri1; /* INTR + 0x04 */ | ||
246 | u32 per_pri2; /* INTR + 0x08 */ | ||
247 | u32 per_pri3; /* INTR + 0x0c */ | ||
248 | u32 ctrl; /* INTR + 0x10 */ | ||
249 | u32 main_mask; /* INTR + 0x14 */ | ||
250 | u32 main_pri1; /* INTR + 0x18 */ | ||
251 | u32 main_pri2; /* INTR + 0x1c */ | ||
252 | u32 reserved1; /* INTR + 0x20 */ | ||
253 | u32 enc_status; /* INTR + 0x24 */ | ||
254 | u32 crit_status; /* INTR + 0x28 */ | ||
255 | u32 main_status; /* INTR + 0x2c */ | ||
256 | u32 per_status; /* INTR + 0x30 */ | ||
257 | u32 reserved2; /* INTR + 0x34 */ | ||
258 | u32 per_error; /* INTR + 0x38 */ | ||
259 | }; | ||
260 | |||
242 | #endif /* __ASSEMBLY__ */ | 261 | #endif /* __ASSEMBLY__ */ |
243 | 262 | ||
244 | 263 | ||
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index fe92e65103ed..b5c753db125e 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c | |||
@@ -3,7 +3,6 @@ | |||
3 | #include <asm/io.h> | 3 | #include <asm/io.h> |
4 | #include <asm/time.h> | 4 | #include <asm/time.h> |
5 | #include <asm/mpc52xx.h> | 5 | #include <asm/mpc52xx.h> |
6 | #include "mpc52xx_pic.h" | ||
7 | 6 | ||
8 | /* defined in lite5200_sleep.S and only used here */ | 7 | /* defined in lite5200_sleep.S and only used here */ |
9 | extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); | 8 | extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 8479394e9ab4..c2fa60e0c421 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c | |||
@@ -2,20 +2,100 @@ | |||
2 | * | 2 | * |
3 | * Programmable Interrupt Controller functions for the Freescale MPC52xx. | 3 | * Programmable Interrupt Controller functions for the Freescale MPC52xx. |
4 | * | 4 | * |
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | ||
5 | * Copyright (C) 2006 bplan GmbH | 6 | * Copyright (C) 2006 bplan GmbH |
7 | * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> | ||
8 | * Copyright (C) 2003 Montavista Software, Inc | ||
6 | * | 9 | * |
7 | * Based on the code from the 2.4 kernel by | 10 | * Based on the code from the 2.4 kernel by |
8 | * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. | 11 | * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. |
9 | * | 12 | * |
10 | * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> | ||
11 | * Copyright (C) 2003 Montavista Software, Inc | ||
12 | * | ||
13 | * This file is licensed under the terms of the GNU General Public License | 13 | * This file is licensed under the terms of the GNU General Public License |
14 | * version 2. This program is licensed "as is" without any warranty of any | 14 | * version 2. This program is licensed "as is" without any warranty of any |
15 | * kind, whether express or implied. | 15 | * kind, whether express or implied. |
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* | ||
20 | * This is the device driver for the MPC5200 interrupt controller. | ||
21 | * | ||
22 | * hardware overview | ||
23 | * ----------------- | ||
24 | * The MPC5200 interrupt controller groups the all interrupt sources into | ||
25 | * three groups called 'critical', 'main', and 'peripheral'. The critical | ||
26 | * group has 3 irqs, External IRQ0, slice timer 0 irq, and wake from deep | ||
27 | * sleep. Main group include the other 3 external IRQs, slice timer 1, RTC, | ||
28 | * gpios, and the general purpose timers. Peripheral group contains the | ||
29 | * remaining irq sources from all of the on-chip peripherals (PSCs, Ethernet, | ||
30 | * USB, DMA, etc). | ||
31 | * | ||
32 | * virqs | ||
33 | * ----- | ||
34 | * The Linux IRQ subsystem requires that each irq source be assigned a | ||
35 | * system wide unique IRQ number starting at 1 (0 means no irq). Since | ||
36 | * systems can have multiple interrupt controllers, the virtual IRQ (virq) | ||
37 | * infrastructure lets each interrupt controller to define a local set | ||
38 | * of IRQ numbers and the virq infrastructure maps those numbers into | ||
39 | * a unique range of the global IRQ# space. | ||
40 | * | ||
41 | * To define a range of virq numbers for this controller, this driver first | ||
42 | * assigns a number to each of the irq groups (called the level 1 or L1 | ||
43 | * value). Within each group individual irq sources are also assigned a | ||
44 | * number, as defined by the MPC5200 user guide, and refers to it as the | ||
45 | * level 2 or L2 value. The virq number is determined by shifting up the | ||
46 | * L1 value by MPC52xx_IRQ_L1_OFFSET and ORing it with the L2 value. | ||
47 | * | ||
48 | * For example, the TMR0 interrupt is irq 9 in the main group. The | ||
49 | * virq for TMR0 is calculated by ((1 << MPC52xx_IRQ_L1_OFFSET) | 9). | ||
50 | * | ||
51 | * The observant reader will also notice that this driver defines a 4th | ||
52 | * interrupt group called 'bestcomm'. The bestcomm group isn't physically | ||
53 | * part of the MPC5200 interrupt controller, but it is used here to assign | ||
54 | * a separate virq number for each bestcomm task (since any of the 16 | ||
55 | * bestcomm tasks can cause the bestcomm interrupt to be raised). When a | ||
56 | * bestcomm interrupt occurs (peripheral group, irq 0) this driver determines | ||
57 | * which task needs servicing and returns the irq number for that task. This | ||
58 | * allows drivers which use bestcomm to define their own interrupt handlers. | ||
59 | * | ||
60 | * irq_chip structures | ||
61 | * ------------------- | ||
62 | * For actually manipulating IRQs (masking, enabling, clearing, etc) this | ||
63 | * driver defines four separate 'irq_chip' structures, one for the main | ||
64 | * group, one for the peripherals group, one for the bestcomm group and one | ||
65 | * for external interrupts. The irq_chip structures provide the hooks needed | ||
66 | * to manipulate each IRQ source, and since each group is has a separate set | ||
67 | * of registers for controlling the irq, it makes sense to divide up the | ||
68 | * hooks along those lines. | ||
69 | * | ||
70 | * You'll notice that there is not an irq_chip for the critical group and | ||
71 | * you'll also notice that there is an irq_chip defined for external | ||
72 | * interrupts even though there is no external interrupt group. The reason | ||
73 | * for this is that the four external interrupts are all managed with the same | ||
74 | * register even though one of the external IRQs is in the critical group and | ||
75 | * the other three are in the main group. For this reason it makes sense for | ||
76 | * the 4 external irqs to be managed using a separate set of hooks. The | ||
77 | * reason there is no crit irq_chip is that of the 3 irqs in the critical | ||
78 | * group, only external interrupt is actually support at this time by this | ||
79 | * driver and since external interrupt is the only one used, it can just | ||
80 | * be directed to make use of the external irq irq_chip. | ||
81 | * | ||
82 | * device tree bindings | ||
83 | * -------------------- | ||
84 | * The device tree bindings for this controller reflect the two level | ||
85 | * organization of irqs in the device. #interrupt-cells = <3> where the | ||
86 | * first cell is the group number [0..3], the second cell is the irq | ||
87 | * number in the group, and the third cell is the sense type (level/edge). | ||
88 | * For reference, the following is a list of the interrupt property values | ||
89 | * associated with external interrupt sources on the MPC5200 (just because | ||
90 | * it is non-obvious to determine what the interrupts property should be | ||
91 | * when reading the mpc5200 manual and it is a frequently asked question). | ||
92 | * | ||
93 | * External interrupts: | ||
94 | * <0 0 n> external irq0, n is sense (n=0: level high, | ||
95 | * <1 1 n> external irq1, n is sense n=1: edge rising, | ||
96 | * <1 2 n> external irq2, n is sense n=2: edge falling, | ||
97 | * <1 3 n> external irq3, n is sense n=3: level low) | ||
98 | */ | ||
19 | #undef DEBUG | 99 | #undef DEBUG |
20 | 100 | ||
21 | #include <linux/interrupt.h> | 101 | #include <linux/interrupt.h> |
@@ -24,11 +104,19 @@ | |||
24 | #include <asm/io.h> | 104 | #include <asm/io.h> |
25 | #include <asm/prom.h> | 105 | #include <asm/prom.h> |
26 | #include <asm/mpc52xx.h> | 106 | #include <asm/mpc52xx.h> |
27 | #include "mpc52xx_pic.h" | ||
28 | 107 | ||
29 | /* | 108 | /* HW IRQ mapping */ |
30 | * | 109 | #define MPC52xx_IRQ_L1_CRIT (0) |
31 | */ | 110 | #define MPC52xx_IRQ_L1_MAIN (1) |
111 | #define MPC52xx_IRQ_L1_PERP (2) | ||
112 | #define MPC52xx_IRQ_L1_SDMA (3) | ||
113 | |||
114 | #define MPC52xx_IRQ_L1_OFFSET (6) | ||
115 | #define MPC52xx_IRQ_L1_MASK (0x00c0) | ||
116 | #define MPC52xx_IRQ_L2_MASK (0x003f) | ||
117 | |||
118 | #define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0) | ||
119 | |||
32 | 120 | ||
33 | /* MPC5200 device tree match tables */ | 121 | /* MPC5200 device tree match tables */ |
34 | static struct of_device_id mpc52xx_pic_ids[] __initdata = { | 122 | static struct of_device_id mpc52xx_pic_ids[] __initdata = { |
@@ -53,10 +141,7 @@ static unsigned char mpc52xx_map_senses[4] = { | |||
53 | IRQ_TYPE_LEVEL_LOW, | 141 | IRQ_TYPE_LEVEL_LOW, |
54 | }; | 142 | }; |
55 | 143 | ||
56 | /* | 144 | /* Utility functions */ |
57 | * | ||
58 | */ | ||
59 | |||
60 | static inline void io_be_setbit(u32 __iomem *addr, int bitno) | 145 | static inline void io_be_setbit(u32 __iomem *addr, int bitno) |
61 | { | 146 | { |
62 | out_be32(addr, in_be32(addr) | (1 << bitno)); | 147 | out_be32(addr, in_be32(addr) | (1 << bitno)); |
@@ -69,15 +154,14 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno) | |||
69 | 154 | ||
70 | /* | 155 | /* |
71 | * IRQ[0-3] interrupt irq_chip | 156 | * IRQ[0-3] interrupt irq_chip |
72 | */ | 157 | */ |
73 | |||
74 | static void mpc52xx_extirq_mask(unsigned int virq) | 158 | static void mpc52xx_extirq_mask(unsigned int virq) |
75 | { | 159 | { |
76 | int irq; | 160 | int irq; |
77 | int l2irq; | 161 | int l2irq; |
78 | 162 | ||
79 | irq = irq_map[virq].hwirq; | 163 | irq = irq_map[virq].hwirq; |
80 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 164 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
81 | 165 | ||
82 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 166 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
83 | 167 | ||
@@ -90,7 +174,7 @@ static void mpc52xx_extirq_unmask(unsigned int virq) | |||
90 | int l2irq; | 174 | int l2irq; |
91 | 175 | ||
92 | irq = irq_map[virq].hwirq; | 176 | irq = irq_map[virq].hwirq; |
93 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 177 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
94 | 178 | ||
95 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 179 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
96 | 180 | ||
@@ -103,7 +187,7 @@ static void mpc52xx_extirq_ack(unsigned int virq) | |||
103 | int l2irq; | 187 | int l2irq; |
104 | 188 | ||
105 | irq = irq_map[virq].hwirq; | 189 | irq = irq_map[virq].hwirq; |
106 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 190 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
107 | 191 | ||
108 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 192 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
109 | 193 | ||
@@ -117,7 +201,7 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) | |||
117 | int l2irq; | 201 | int l2irq; |
118 | 202 | ||
119 | irq = irq_map[virq].hwirq; | 203 | irq = irq_map[virq].hwirq; |
120 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 204 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
121 | 205 | ||
122 | pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); | 206 | pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); |
123 | 207 | ||
@@ -156,15 +240,14 @@ static struct irq_chip mpc52xx_extirq_irqchip = { | |||
156 | 240 | ||
157 | /* | 241 | /* |
158 | * Main interrupt irq_chip | 242 | * Main interrupt irq_chip |
159 | */ | 243 | */ |
160 | |||
161 | static void mpc52xx_main_mask(unsigned int virq) | 244 | static void mpc52xx_main_mask(unsigned int virq) |
162 | { | 245 | { |
163 | int irq; | 246 | int irq; |
164 | int l2irq; | 247 | int l2irq; |
165 | 248 | ||
166 | irq = irq_map[virq].hwirq; | 249 | irq = irq_map[virq].hwirq; |
167 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 250 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
168 | 251 | ||
169 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 252 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
170 | 253 | ||
@@ -177,7 +260,7 @@ static void mpc52xx_main_unmask(unsigned int virq) | |||
177 | int l2irq; | 260 | int l2irq; |
178 | 261 | ||
179 | irq = irq_map[virq].hwirq; | 262 | irq = irq_map[virq].hwirq; |
180 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 263 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
181 | 264 | ||
182 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 265 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
183 | 266 | ||
@@ -193,15 +276,14 @@ static struct irq_chip mpc52xx_main_irqchip = { | |||
193 | 276 | ||
194 | /* | 277 | /* |
195 | * Peripherals interrupt irq_chip | 278 | * Peripherals interrupt irq_chip |
196 | */ | 279 | */ |
197 | |||
198 | static void mpc52xx_periph_mask(unsigned int virq) | 280 | static void mpc52xx_periph_mask(unsigned int virq) |
199 | { | 281 | { |
200 | int irq; | 282 | int irq; |
201 | int l2irq; | 283 | int l2irq; |
202 | 284 | ||
203 | irq = irq_map[virq].hwirq; | 285 | irq = irq_map[virq].hwirq; |
204 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 286 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
205 | 287 | ||
206 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 288 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
207 | 289 | ||
@@ -214,7 +296,7 @@ static void mpc52xx_periph_unmask(unsigned int virq) | |||
214 | int l2irq; | 296 | int l2irq; |
215 | 297 | ||
216 | irq = irq_map[virq].hwirq; | 298 | irq = irq_map[virq].hwirq; |
217 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 299 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
218 | 300 | ||
219 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 301 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
220 | 302 | ||
@@ -230,15 +312,14 @@ static struct irq_chip mpc52xx_periph_irqchip = { | |||
230 | 312 | ||
231 | /* | 313 | /* |
232 | * SDMA interrupt irq_chip | 314 | * SDMA interrupt irq_chip |
233 | */ | 315 | */ |
234 | |||
235 | static void mpc52xx_sdma_mask(unsigned int virq) | 316 | static void mpc52xx_sdma_mask(unsigned int virq) |
236 | { | 317 | { |
237 | int irq; | 318 | int irq; |
238 | int l2irq; | 319 | int l2irq; |
239 | 320 | ||
240 | irq = irq_map[virq].hwirq; | 321 | irq = irq_map[virq].hwirq; |
241 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 322 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
242 | 323 | ||
243 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 324 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
244 | 325 | ||
@@ -251,7 +332,7 @@ static void mpc52xx_sdma_unmask(unsigned int virq) | |||
251 | int l2irq; | 332 | int l2irq; |
252 | 333 | ||
253 | irq = irq_map[virq].hwirq; | 334 | irq = irq_map[virq].hwirq; |
254 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 335 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
255 | 336 | ||
256 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 337 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
257 | 338 | ||
@@ -264,7 +345,7 @@ static void mpc52xx_sdma_ack(unsigned int virq) | |||
264 | int l2irq; | 345 | int l2irq; |
265 | 346 | ||
266 | irq = irq_map[virq].hwirq; | 347 | irq = irq_map[virq].hwirq; |
267 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 348 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
268 | 349 | ||
269 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | 350 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); |
270 | 351 | ||
@@ -278,13 +359,12 @@ static struct irq_chip mpc52xx_sdma_irqchip = { | |||
278 | .ack = mpc52xx_sdma_ack, | 359 | .ack = mpc52xx_sdma_ack, |
279 | }; | 360 | }; |
280 | 361 | ||
281 | /* | 362 | /** |
282 | * irq_host | 363 | * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property |
283 | */ | 364 | */ |
284 | |||
285 | static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, | 365 | static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, |
286 | u32 * intspec, unsigned int intsize, | 366 | u32 *intspec, unsigned int intsize, |
287 | irq_hw_number_t * out_hwirq, | 367 | irq_hw_number_t *out_hwirq, |
288 | unsigned int *out_flags) | 368 | unsigned int *out_flags) |
289 | { | 369 | { |
290 | int intrvect_l1; | 370 | int intrvect_l1; |
@@ -299,10 +379,9 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, | |||
299 | intrvect_l2 = (int)intspec[1]; | 379 | intrvect_l2 = (int)intspec[1]; |
300 | intrvect_type = (int)intspec[2]; | 380 | intrvect_type = (int)intspec[2]; |
301 | 381 | ||
302 | intrvect_linux = | 382 | intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & |
303 | (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; | 383 | MPC52xx_IRQ_L1_MASK; |
304 | intrvect_linux |= | 384 | intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK; |
305 | (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; | ||
306 | 385 | ||
307 | pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, | 386 | pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, |
308 | intrvect_l2); | 387 | intrvect_l2); |
@@ -313,11 +392,11 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, | |||
313 | return 0; | 392 | return 0; |
314 | } | 393 | } |
315 | 394 | ||
316 | /* | 395 | /** |
317 | * this function retrieves the correct IRQ type out | 396 | * mpc52xx_irqx_gettype - determine the IRQ sense type (level/edge) |
318 | * of the MPC regs | 397 | * |
319 | * Only externals IRQs needs this | 398 | * Only external IRQs need this. |
320 | */ | 399 | */ |
321 | static int mpc52xx_irqx_gettype(int irq) | 400 | static int mpc52xx_irqx_gettype(int irq) |
322 | { | 401 | { |
323 | int type; | 402 | int type; |
@@ -329,6 +408,9 @@ static int mpc52xx_irqx_gettype(int irq) | |||
329 | return mpc52xx_map_senses[type]; | 408 | return mpc52xx_map_senses[type]; |
330 | } | 409 | } |
331 | 410 | ||
411 | /** | ||
412 | * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure | ||
413 | */ | ||
332 | static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, | 414 | static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, |
333 | irq_hw_number_t irq) | 415 | irq_hw_number_t irq) |
334 | { | 416 | { |
@@ -339,7 +421,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, | |||
339 | int type; | 421 | int type; |
340 | 422 | ||
341 | l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; | 423 | l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; |
342 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | 424 | l2irq = irq & MPC52xx_IRQ_L2_MASK; |
343 | 425 | ||
344 | /* | 426 | /* |
345 | * Most of ours IRQs will be level low | 427 | * Most of ours IRQs will be level low |
@@ -379,8 +461,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, | |||
379 | break; | 461 | break; |
380 | 462 | ||
381 | default: | 463 | default: |
382 | pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq); | 464 | pr_err("%s: invalid virq requested (0x%x)\n", __func__, virq); |
383 | printk(KERN_ERR "Unknow IRQ!\n"); | ||
384 | return -EINVAL; | 465 | return -EINVAL; |
385 | } | 466 | } |
386 | 467 | ||
@@ -406,10 +487,15 @@ static struct irq_host_ops mpc52xx_irqhost_ops = { | |||
406 | .map = mpc52xx_irqhost_map, | 487 | .map = mpc52xx_irqhost_map, |
407 | }; | 488 | }; |
408 | 489 | ||
409 | /* | 490 | /** |
410 | * init (public) | 491 | * mpc52xx_init_irq - Initialize and register with the virq subsystem |
411 | */ | 492 | * |
412 | 493 | * Hook for setting up IRQs on an mpc5200 system. A pointer to this function | |
494 | * is to be put into the machine definition structure. | ||
495 | * | ||
496 | * This function searches the device tree for an MPC5200 interrupt controller, | ||
497 | * initializes it, and registers it with the virq subsystem. | ||
498 | */ | ||
413 | void __init mpc52xx_init_irq(void) | 499 | void __init mpc52xx_init_irq(void) |
414 | { | 500 | { |
415 | u32 intr_ctrl; | 501 | u32 intr_ctrl; |
@@ -454,7 +540,6 @@ void __init mpc52xx_init_irq(void) | |||
454 | * As last step, add an irq host to translate the real | 540 | * As last step, add an irq host to translate the real |
455 | * hw irq information provided by the ofw to linux virq | 541 | * hw irq information provided by the ofw to linux virq |
456 | */ | 542 | */ |
457 | |||
458 | mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, | 543 | mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, |
459 | MPC52xx_IRQ_HIGHTESTHWIRQ, | 544 | MPC52xx_IRQ_HIGHTESTHWIRQ, |
460 | &mpc52xx_irqhost_ops, -1); | 545 | &mpc52xx_irqhost_ops, -1); |
@@ -462,12 +547,36 @@ void __init mpc52xx_init_irq(void) | |||
462 | if (!mpc52xx_irqhost) | 547 | if (!mpc52xx_irqhost) |
463 | panic(__FILE__ ": Cannot allocate the IRQ host\n"); | 548 | panic(__FILE__ ": Cannot allocate the IRQ host\n"); |
464 | 549 | ||
465 | printk(KERN_INFO "MPC52xx PIC is up and running!\n"); | 550 | pr_info("MPC52xx PIC is up and running!\n"); |
466 | } | 551 | } |
467 | 552 | ||
468 | /* | 553 | /** |
469 | * get_irq (public) | 554 | * mpc52xx_get_irq - Get pending interrupt number hook function |
470 | */ | 555 | * |
556 | * Called by the interupt handler to determine what IRQ handler needs to be | ||
557 | * executed. | ||
558 | * | ||
559 | * Status of pending interrupts is determined by reading the encoded status | ||
560 | * register. The encoded status register has three fields; one for each of the | ||
561 | * types of interrupts defined by the controller - 'critical', 'main' and | ||
562 | * 'peripheral'. This function reads the status register and returns the IRQ | ||
563 | * number associated with the highest priority pending interrupt. 'Critical' | ||
564 | * interrupts have the highest priority, followed by 'main' interrupts, and | ||
565 | * then 'peripheral'. | ||
566 | * | ||
567 | * The mpc5200 interrupt controller can be configured to boost the priority | ||
568 | * of individual 'peripheral' interrupts. If this is the case then a special | ||
569 | * value will appear in either the crit or main fields indicating a high | ||
570 | * or medium priority peripheral irq has occurred. | ||
571 | * | ||
572 | * This function checks each of the 3 irq request fields and returns the | ||
573 | * first pending interrupt that it finds. | ||
574 | * | ||
575 | * This function also identifies a 4th type of interrupt; 'bestcomm'. Each | ||
576 | * bestcomm DMA task can raise the bestcomm peripheral interrupt. When this | ||
577 | * occurs at task-specific IRQ# is decoded so that each task can have its | ||
578 | * own IRQ handler. | ||
579 | */ | ||
471 | unsigned int mpc52xx_get_irq(void) | 580 | unsigned int mpc52xx_get_irq(void) |
472 | { | 581 | { |
473 | u32 status; | 582 | u32 status; |
@@ -478,25 +587,21 @@ unsigned int mpc52xx_get_irq(void) | |||
478 | irq = (status >> 8) & 0x3; | 587 | irq = (status >> 8) & 0x3; |
479 | if (irq == 2) /* high priority peripheral */ | 588 | if (irq == 2) /* high priority peripheral */ |
480 | goto peripheral; | 589 | goto peripheral; |
481 | irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & | 590 | irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET); |
482 | MPC52xx_IRQ_L1_MASK; | ||
483 | } else if (status & 0x00200000) { /* main */ | 591 | } else if (status & 0x00200000) { /* main */ |
484 | irq = (status >> 16) & 0x1f; | 592 | irq = (status >> 16) & 0x1f; |
485 | if (irq == 4) /* low priority peripheral */ | 593 | if (irq == 4) /* low priority peripheral */ |
486 | goto peripheral; | 594 | goto peripheral; |
487 | irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & | 595 | irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET); |
488 | MPC52xx_IRQ_L1_MASK; | ||
489 | } else if (status & 0x20000000) { /* peripheral */ | 596 | } else if (status & 0x20000000) { /* peripheral */ |
490 | peripheral: | 597 | peripheral: |
491 | irq = (status >> 24) & 0x1f; | 598 | irq = (status >> 24) & 0x1f; |
492 | if (irq == 0) { /* bestcomm */ | 599 | if (irq == 0) { /* bestcomm */ |
493 | status = in_be32(&sdma->IntPend); | 600 | status = in_be32(&sdma->IntPend); |
494 | irq = ffs(status) - 1; | 601 | irq = ffs(status) - 1; |
495 | irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & | 602 | irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET); |
496 | MPC52xx_IRQ_L1_MASK; | ||
497 | } else { | 603 | } else { |
498 | irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & | 604 | irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET); |
499 | MPC52xx_IRQ_L1_MASK; | ||
500 | } | 605 | } |
501 | } | 606 | } |
502 | 607 | ||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.h b/arch/powerpc/platforms/52xx/mpc52xx_pic.h deleted file mode 100644 index 1a26bcdb3049..000000000000 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | /* | ||
2 | * Header file for Freescale MPC52xx Interrupt controller | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com> | ||
5 | * Copyright (C) 2003 MontaVista, Software, Inc. | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public License | ||
8 | * version 2. This program is licensed "as is" without any warranty of any | ||
9 | * kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #ifndef __POWERPC_SYSDEV_MPC52xx_PIC_H__ | ||
13 | #define __POWERPC_SYSDEV_MPC52xx_PIC_H__ | ||
14 | |||
15 | #include <asm/types.h> | ||
16 | |||
17 | |||
18 | /* HW IRQ mapping */ | ||
19 | #define MPC52xx_IRQ_L1_CRIT (0) | ||
20 | #define MPC52xx_IRQ_L1_MAIN (1) | ||
21 | #define MPC52xx_IRQ_L1_PERP (2) | ||
22 | #define MPC52xx_IRQ_L1_SDMA (3) | ||
23 | |||
24 | #define MPC52xx_IRQ_L1_OFFSET (6) | ||
25 | #define MPC52xx_IRQ_L1_MASK (0x00c0) | ||
26 | |||
27 | #define MPC52xx_IRQ_L2_OFFSET (0) | ||
28 | #define MPC52xx_IRQ_L2_MASK (0x003f) | ||
29 | |||
30 | #define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0) | ||
31 | |||
32 | |||
33 | /* Interrupt controller Register set */ | ||
34 | struct mpc52xx_intr { | ||
35 | u32 per_mask; /* INTR + 0x00 */ | ||
36 | u32 per_pri1; /* INTR + 0x04 */ | ||
37 | u32 per_pri2; /* INTR + 0x08 */ | ||
38 | u32 per_pri3; /* INTR + 0x0c */ | ||
39 | u32 ctrl; /* INTR + 0x10 */ | ||
40 | u32 main_mask; /* INTR + 0x14 */ | ||
41 | u32 main_pri1; /* INTR + 0x18 */ | ||
42 | u32 main_pri2; /* INTR + 0x1c */ | ||
43 | u32 reserved1; /* INTR + 0x20 */ | ||
44 | u32 enc_status; /* INTR + 0x24 */ | ||
45 | u32 crit_status; /* INTR + 0x28 */ | ||
46 | u32 main_status; /* INTR + 0x2c */ | ||
47 | u32 per_status; /* INTR + 0x30 */ | ||
48 | u32 reserved2; /* INTR + 0x34 */ | ||
49 | u32 per_error; /* INTR + 0x38 */ | ||
50 | }; | ||
51 | |||
52 | #endif /* __POWERPC_SYSDEV_MPC52xx_PIC_H__ */ | ||
53 | |||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index c72d3304387f..a55b0b6813ed 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c | |||
@@ -5,9 +5,6 @@ | |||
5 | #include <asm/cacheflush.h> | 5 | #include <asm/cacheflush.h> |
6 | #include <asm/mpc52xx.h> | 6 | #include <asm/mpc52xx.h> |
7 | 7 | ||
8 | #include "mpc52xx_pic.h" | ||
9 | |||
10 | |||
11 | /* these are defined in mpc52xx_sleep.S, and only used here */ | 8 | /* these are defined in mpc52xx_sleep.S, and only used here */ |
12 | extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs, | 9 | extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs, |
13 | struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*); | 10 | struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*); |