]>
Commit | Line | Data |
---|---|---|
d4a67d9d GJ |
1 | /* |
2 | * Atheros AR71xx/AR724x/AR913x specific interrupt handling | |
3 | * | |
4 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | |
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | |
6 | * | |
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License version 2 as published | |
11 | * by the Free Software Foundation. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/irq.h> | |
18 | ||
19 | #include <asm/irq_cpu.h> | |
20 | #include <asm/mipsregs.h> | |
21 | ||
22 | #include <asm/mach-ath79/ath79.h> | |
23 | #include <asm/mach-ath79/ar71xx_regs.h> | |
24 | #include "common.h" | |
25 | ||
26 | static unsigned int ath79_ip2_flush_reg; | |
27 | static unsigned int ath79_ip3_flush_reg; | |
28 | ||
29 | static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) | |
30 | { | |
31 | void __iomem *base = ath79_reset_base; | |
32 | u32 pending; | |
33 | ||
34 | pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & | |
35 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | |
36 | ||
37 | if (pending & MISC_INT_UART) | |
38 | generic_handle_irq(ATH79_MISC_IRQ_UART); | |
39 | ||
40 | else if (pending & MISC_INT_DMA) | |
41 | generic_handle_irq(ATH79_MISC_IRQ_DMA); | |
42 | ||
43 | else if (pending & MISC_INT_PERFC) | |
44 | generic_handle_irq(ATH79_MISC_IRQ_PERFC); | |
45 | ||
46 | else if (pending & MISC_INT_TIMER) | |
47 | generic_handle_irq(ATH79_MISC_IRQ_TIMER); | |
48 | ||
d2b4ac1e GJ |
49 | else if (pending & MISC_INT_TIMER2) |
50 | generic_handle_irq(ATH79_MISC_IRQ_TIMER2); | |
51 | ||
52 | else if (pending & MISC_INT_TIMER3) | |
53 | generic_handle_irq(ATH79_MISC_IRQ_TIMER3); | |
54 | ||
55 | else if (pending & MISC_INT_TIMER4) | |
56 | generic_handle_irq(ATH79_MISC_IRQ_TIMER4); | |
57 | ||
d4a67d9d GJ |
58 | else if (pending & MISC_INT_OHCI) |
59 | generic_handle_irq(ATH79_MISC_IRQ_OHCI); | |
60 | ||
61 | else if (pending & MISC_INT_ERROR) | |
62 | generic_handle_irq(ATH79_MISC_IRQ_ERROR); | |
63 | ||
64 | else if (pending & MISC_INT_GPIO) | |
65 | generic_handle_irq(ATH79_MISC_IRQ_GPIO); | |
66 | ||
67 | else if (pending & MISC_INT_WDOG) | |
68 | generic_handle_irq(ATH79_MISC_IRQ_WDOG); | |
69 | ||
d2b4ac1e GJ |
70 | else if (pending & MISC_INT_ETHSW) |
71 | generic_handle_irq(ATH79_MISC_IRQ_ETHSW); | |
72 | ||
d4a67d9d GJ |
73 | else |
74 | spurious_interrupt(); | |
75 | } | |
76 | ||
3fb8818b | 77 | static void ar71xx_misc_irq_unmask(struct irq_data *d) |
d4a67d9d | 78 | { |
3fb8818b | 79 | unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE; |
d4a67d9d GJ |
80 | void __iomem *base = ath79_reset_base; |
81 | u32 t; | |
82 | ||
d4a67d9d GJ |
83 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
84 | __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | |
85 | ||
86 | /* flush write */ | |
87 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | |
88 | } | |
89 | ||
3fb8818b | 90 | static void ar71xx_misc_irq_mask(struct irq_data *d) |
d4a67d9d | 91 | { |
3fb8818b | 92 | unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE; |
d4a67d9d GJ |
93 | void __iomem *base = ath79_reset_base; |
94 | u32 t; | |
95 | ||
d4a67d9d GJ |
96 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
97 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | |
98 | ||
99 | /* flush write */ | |
100 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | |
101 | } | |
102 | ||
3fb8818b | 103 | static void ar724x_misc_irq_ack(struct irq_data *d) |
d4a67d9d | 104 | { |
3fb8818b | 105 | unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE; |
d4a67d9d GJ |
106 | void __iomem *base = ath79_reset_base; |
107 | u32 t; | |
108 | ||
d4a67d9d GJ |
109 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); |
110 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); | |
111 | ||
112 | /* flush write */ | |
113 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); | |
114 | } | |
115 | ||
116 | static struct irq_chip ath79_misc_irq_chip = { | |
117 | .name = "MISC", | |
3fb8818b TG |
118 | .irq_unmask = ar71xx_misc_irq_unmask, |
119 | .irq_mask = ar71xx_misc_irq_mask, | |
d4a67d9d GJ |
120 | }; |
121 | ||
122 | static void __init ath79_misc_irq_init(void) | |
123 | { | |
124 | void __iomem *base = ath79_reset_base; | |
125 | int i; | |
126 | ||
127 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); | |
128 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); | |
129 | ||
130 | if (soc_is_ar71xx() || soc_is_ar913x()) | |
3fb8818b | 131 | ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; |
54eed4c7 | 132 | else if (soc_is_ar724x() || soc_is_ar933x()) |
3fb8818b | 133 | ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; |
d4a67d9d GJ |
134 | else |
135 | BUG(); | |
136 | ||
137 | for (i = ATH79_MISC_IRQ_BASE; | |
138 | i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) { | |
e4ec7989 | 139 | irq_set_chip_and_handler(i, &ath79_misc_irq_chip, |
d4a67d9d GJ |
140 | handle_level_irq); |
141 | } | |
142 | ||
e4ec7989 | 143 | irq_set_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler); |
d4a67d9d GJ |
144 | } |
145 | ||
146 | asmlinkage void plat_irq_dispatch(void) | |
147 | { | |
148 | unsigned long pending; | |
149 | ||
150 | pending = read_c0_status() & read_c0_cause() & ST0_IM; | |
151 | ||
152 | if (pending & STATUSF_IP7) | |
153 | do_IRQ(ATH79_CPU_IRQ_TIMER); | |
154 | ||
155 | else if (pending & STATUSF_IP2) { | |
156 | ath79_ddr_wb_flush(ath79_ip2_flush_reg); | |
157 | do_IRQ(ATH79_CPU_IRQ_IP2); | |
158 | } | |
159 | ||
160 | else if (pending & STATUSF_IP4) | |
161 | do_IRQ(ATH79_CPU_IRQ_GE0); | |
162 | ||
163 | else if (pending & STATUSF_IP5) | |
164 | do_IRQ(ATH79_CPU_IRQ_GE1); | |
165 | ||
166 | else if (pending & STATUSF_IP3) { | |
167 | ath79_ddr_wb_flush(ath79_ip3_flush_reg); | |
168 | do_IRQ(ATH79_CPU_IRQ_USB); | |
169 | } | |
170 | ||
171 | else if (pending & STATUSF_IP6) | |
172 | do_IRQ(ATH79_CPU_IRQ_MISC); | |
173 | ||
174 | else | |
175 | spurious_interrupt(); | |
176 | } | |
177 | ||
178 | void __init arch_init_irq(void) | |
179 | { | |
180 | if (soc_is_ar71xx()) { | |
181 | ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; | |
182 | ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB; | |
183 | } else if (soc_is_ar724x()) { | |
184 | ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; | |
185 | ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB; | |
186 | } else if (soc_is_ar913x()) { | |
187 | ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC; | |
188 | ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB; | |
54eed4c7 GJ |
189 | } else if (soc_is_ar933x()) { |
190 | ath79_ip2_flush_reg = AR933X_DDR_REG_FLUSH_WMAC; | |
191 | ath79_ip3_flush_reg = AR933X_DDR_REG_FLUSH_USB; | |
d4a67d9d GJ |
192 | } else |
193 | BUG(); | |
194 | ||
195 | cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; | |
196 | mips_cpu_irq_init(); | |
197 | ath79_misc_irq_init(); | |
198 | } |