diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2012-03-14 05:36:07 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-05-15 11:49:04 -0400 |
commit | 4c07c7dfa0f3575dc3276c544349fbf181381167 (patch) | |
tree | 4b39750ce1284ec0032b21508fa56a8201a7dea1 /arch | |
parent | 93ef85b5598ad2cc23f38d97ed565027b969c0aa (diff) |
MIPS: ath79: add PCI IRQ handling code for AR724X SoCs
The PCI Host Controller of the AR724x SoC has a
built-in IRQ controller. The current code does
not supports that, so the IRQ lines wired to this
controller are not usable. This leads to failed
'request_irq' calls:
ath9k 0000:00:00.0: request_irq failed
ath9k: probe of 0000:00:00.0 failed with error -89
This patch adds support for the IRQ controller
in order to make PCI IRQs work.
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3496/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/ath79/pci.c | 3 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-ath79/pci.h | 4 | ||||
-rw-r--r-- | arch/mips/pci/pci-ar724x.c | 118 |
3 files changed, 120 insertions, 5 deletions
diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c index 72281fb5360f..14f981c295d2 100644 --- a/arch/mips/ath79/pci.c +++ b/arch/mips/ath79/pci.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | #include <asm/mach-ath79/ath79.h> | 12 | #include <asm/mach-ath79/ath79.h> |
13 | #include <asm/mach-ath79/irq.h> | ||
13 | #include <asm/mach-ath79/pci.h> | 14 | #include <asm/mach-ath79/pci.h> |
14 | #include "pci.h" | 15 | #include "pci.h" |
15 | 16 | ||
@@ -50,7 +51,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) | |||
50 | int __init ath79_register_pci(void) | 51 | int __init ath79_register_pci(void) |
51 | { | 52 | { |
52 | if (soc_is_ar724x()) | 53 | if (soc_is_ar724x()) |
53 | return ar724x_pcibios_init(); | 54 | return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); |
54 | 55 | ||
55 | return -ENODEV; | 56 | return -ENODEV; |
56 | } | 57 | } |
diff --git a/arch/mips/include/asm/mach-ath79/pci.h b/arch/mips/include/asm/mach-ath79/pci.h index 6d7a837e6055..2eb01815d54e 100644 --- a/arch/mips/include/asm/mach-ath79/pci.h +++ b/arch/mips/include/asm/mach-ath79/pci.h | |||
@@ -12,9 +12,9 @@ | |||
12 | #define __ASM_MACH_ATH79_PCI_H | 12 | #define __ASM_MACH_ATH79_PCI_H |
13 | 13 | ||
14 | #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) | 14 | #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) |
15 | int ar724x_pcibios_init(void); | 15 | int ar724x_pcibios_init(int irq); |
16 | #else | 16 | #else |
17 | static inline int ar724x_pcibios_init(void) { return 0; } | 17 | static inline int ar724x_pcibios_init(int irq) { return 0; } |
18 | #endif | 18 | #endif |
19 | 19 | ||
20 | #endif /* __ASM_MACH_ATH79_PCI_H */ | 20 | #endif /* __ASM_MACH_ATH79_PCI_H */ |
diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 07b7e3071735..04f433a823da 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c | |||
@@ -8,19 +8,32 @@ | |||
8 | * by the Free Software Foundation. | 8 | * by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/irq.h> | ||
11 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
12 | #include <asm/mach-ath79/ath79.h> | 13 | #include <asm/mach-ath79/ath79.h> |
14 | #include <asm/mach-ath79/ar71xx_regs.h> | ||
13 | #include <asm/mach-ath79/pci.h> | 15 | #include <asm/mach-ath79/pci.h> |
14 | 16 | ||
15 | #define AR724X_PCI_CFG_BASE 0x14000000 | 17 | #define AR724X_PCI_CFG_BASE 0x14000000 |
16 | #define AR724X_PCI_CFG_SIZE 0x1000 | 18 | #define AR724X_PCI_CFG_SIZE 0x1000 |
19 | #define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) | ||
20 | #define AR724X_PCI_CTRL_SIZE 0x100 | ||
21 | |||
17 | #define AR724X_PCI_MEM_BASE 0x10000000 | 22 | #define AR724X_PCI_MEM_BASE 0x10000000 |
18 | #define AR724X_PCI_MEM_SIZE 0x08000000 | 23 | #define AR724X_PCI_MEM_SIZE 0x08000000 |
19 | 24 | ||
25 | #define AR724X_PCI_REG_INT_STATUS 0x4c | ||
26 | #define AR724X_PCI_REG_INT_MASK 0x50 | ||
27 | |||
28 | #define AR724X_PCI_INT_DEV0 BIT(14) | ||
29 | |||
30 | #define AR724X_PCI_IRQ_COUNT 1 | ||
31 | |||
20 | #define AR7240_BAR0_WAR_VALUE 0xffff | 32 | #define AR7240_BAR0_WAR_VALUE 0xffff |
21 | 33 | ||
22 | static DEFINE_SPINLOCK(ar724x_pci_lock); | 34 | static DEFINE_SPINLOCK(ar724x_pci_lock); |
23 | static void __iomem *ar724x_pci_devcfg_base; | 35 | static void __iomem *ar724x_pci_devcfg_base; |
36 | static void __iomem *ar724x_pci_ctrl_base; | ||
24 | 37 | ||
25 | static u32 ar724x_pci_bar0_value; | 38 | static u32 ar724x_pci_bar0_value; |
26 | static bool ar724x_pci_bar0_is_cached; | 39 | static bool ar724x_pci_bar0_is_cached; |
@@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_controller = { | |||
164 | .mem_resource = &ar724x_mem_resource, | 177 | .mem_resource = &ar724x_mem_resource, |
165 | }; | 178 | }; |
166 | 179 | ||
167 | int __init ar724x_pcibios_init(void) | 180 | static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) |
181 | { | ||
182 | void __iomem *base; | ||
183 | u32 pending; | ||
184 | |||
185 | base = ar724x_pci_ctrl_base; | ||
186 | |||
187 | pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & | ||
188 | __raw_readl(base + AR724X_PCI_REG_INT_MASK); | ||
189 | |||
190 | if (pending & AR724X_PCI_INT_DEV0) | ||
191 | generic_handle_irq(ATH79_PCI_IRQ(0)); | ||
192 | |||
193 | else | ||
194 | spurious_interrupt(); | ||
195 | } | ||
196 | |||
197 | static void ar724x_pci_irq_unmask(struct irq_data *d) | ||
198 | { | ||
199 | void __iomem *base; | ||
200 | u32 t; | ||
201 | |||
202 | base = ar724x_pci_ctrl_base; | ||
203 | |||
204 | switch (d->irq) { | ||
205 | case ATH79_PCI_IRQ(0): | ||
206 | t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); | ||
207 | __raw_writel(t | AR724X_PCI_INT_DEV0, | ||
208 | base + AR724X_PCI_REG_INT_MASK); | ||
209 | /* flush write */ | ||
210 | __raw_readl(base + AR724X_PCI_REG_INT_MASK); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static void ar724x_pci_irq_mask(struct irq_data *d) | ||
215 | { | ||
216 | void __iomem *base; | ||
217 | u32 t; | ||
218 | |||
219 | base = ar724x_pci_ctrl_base; | ||
220 | |||
221 | switch (d->irq) { | ||
222 | case ATH79_PCI_IRQ(0): | ||
223 | t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); | ||
224 | __raw_writel(t & ~AR724X_PCI_INT_DEV0, | ||
225 | base + AR724X_PCI_REG_INT_MASK); | ||
226 | |||
227 | /* flush write */ | ||
228 | __raw_readl(base + AR724X_PCI_REG_INT_MASK); | ||
229 | |||
230 | t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS); | ||
231 | __raw_writel(t | AR724X_PCI_INT_DEV0, | ||
232 | base + AR724X_PCI_REG_INT_STATUS); | ||
233 | |||
234 | /* flush write */ | ||
235 | __raw_readl(base + AR724X_PCI_REG_INT_STATUS); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static struct irq_chip ar724x_pci_irq_chip = { | ||
240 | .name = "AR724X PCI ", | ||
241 | .irq_mask = ar724x_pci_irq_mask, | ||
242 | .irq_unmask = ar724x_pci_irq_unmask, | ||
243 | .irq_mask_ack = ar724x_pci_irq_mask, | ||
244 | }; | ||
245 | |||
246 | static void __init ar724x_pci_irq_init(int irq) | ||
247 | { | ||
248 | void __iomem *base; | ||
249 | int i; | ||
250 | |||
251 | base = ar724x_pci_ctrl_base; | ||
252 | |||
253 | __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); | ||
254 | __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); | ||
255 | |||
256 | BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); | ||
257 | |||
258 | for (i = ATH79_PCI_IRQ_BASE; | ||
259 | i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) | ||
260 | irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, | ||
261 | handle_level_irq); | ||
262 | |||
263 | irq_set_chained_handler(irq, ar724x_pci_irq_handler); | ||
264 | } | ||
265 | |||
266 | int __init ar724x_pcibios_init(int irq) | ||
168 | { | 267 | { |
268 | int ret; | ||
269 | |||
270 | ret = -ENOMEM; | ||
271 | |||
169 | ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, | 272 | ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, |
170 | AR724X_PCI_CFG_SIZE); | 273 | AR724X_PCI_CFG_SIZE); |
171 | if (ar724x_pci_devcfg_base == NULL) | 274 | if (ar724x_pci_devcfg_base == NULL) |
172 | return -ENOMEM; | 275 | goto err; |
173 | 276 | ||
277 | ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE, | ||
278 | AR724X_PCI_CTRL_SIZE); | ||
279 | if (ar724x_pci_ctrl_base == NULL) | ||
280 | goto err_unmap_devcfg; | ||
281 | |||
282 | ar724x_pci_irq_init(irq); | ||
174 | register_pci_controller(&ar724x_pci_controller); | 283 | register_pci_controller(&ar724x_pci_controller); |
175 | 284 | ||
176 | return PCIBIOS_SUCCESSFUL; | 285 | return PCIBIOS_SUCCESSFUL; |
286 | |||
287 | err_unmap_devcfg: | ||
288 | iounmap(ar724x_pci_devcfg_base); | ||
289 | err: | ||
290 | return ret; | ||
177 | } | 291 | } |