ar71xx: add initial support for 3.2
[openwrt.git] / target / linux / ar71xx / patches-3.2 / 113-MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch
1 From a4fbc2dec67a5d760e25e3c3a6c392191a5405c6 Mon Sep 17 00:00:00 2001
2 From: Gabor Juhos <juhosg@openwrt.org>
3 Date: Tue, 22 Nov 2011 14:11:19 +0100
4 Subject: [PATCH 13/35] MIPS: ath79: add PCI IRQ handling code for AR724X SoCs
5
6 The PCI Host Controller of the AR724x SoC has a
7 built-in IRQ controller. The current code does
8 not supports that, so the IRQ lines wired to this
9 controller are not usable. This leads to failed
10 'request_irq' calls:
11
12   ath9k 0000:00:00.0: request_irq failed
13   ath9k: probe of 0000:00:00.0 failed with error -89
14
15 This patch adds support for the IRQ controller
16 in order to make PCI IRQs work.
17
18 Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
19
20 v2: - move the interrupt controller related defines from
21       the workaround patch
22 ---
23  arch/mips/ath79/pci.c                  |    3 +-
24  arch/mips/include/asm/mach-ath79/pci.h |    4 +-
25  arch/mips/pci/pci-ar724x.c             |  118 +++++++++++++++++++++++++++++++-
26  3 files changed, 120 insertions(+), 5 deletions(-)
27
28 --- a/arch/mips/ath79/pci.c
29 +++ b/arch/mips/ath79/pci.c
30 @@ -10,6 +10,7 @@
31  
32  #include <linux/pci.h>
33  #include <asm/mach-ath79/ath79.h>
34 +#include <asm/mach-ath79/irq.h>
35  #include <asm/mach-ath79/pci.h>
36  #include "pci.h"
37  
38 @@ -50,7 +51,7 @@ int pcibios_plat_dev_init(struct pci_dev
39  int __init ath79_register_pci(void)
40  {
41         if (soc_is_ar724x())
42 -               return ar724x_pcibios_init();
43 +               return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2);
44  
45         return -ENODEV;
46  }
47 --- a/arch/mips/include/asm/mach-ath79/pci.h
48 +++ b/arch/mips/include/asm/mach-ath79/pci.h
49 @@ -12,9 +12,9 @@
50  #define __ASM_MACH_ATH79_PCI_H
51  
52  #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X)
53 -int ar724x_pcibios_init(void);
54 +int ar724x_pcibios_init(int irq);
55  #else
56 -static inline int ar724x_pcibios_init(void) { return 0 };
57 +static inline int ar724x_pcibios_init(int irq) { return 0 };
58  #endif
59  
60  #endif /* __ASM_MACH_ATH79_PCI_H */
61 --- a/arch/mips/pci/pci-ar724x.c
62 +++ b/arch/mips/pci/pci-ar724x.c
63 @@ -8,19 +8,32 @@
64   *  by the Free Software Foundation.
65   */
66  
67 +#include <linux/irq.h>
68  #include <linux/pci.h>
69  #include <asm/mach-ath79/ath79.h>
70 +#include <asm/mach-ath79/ar71xx_regs.h>
71  #include <asm/mach-ath79/pci.h>
72  
73  #define AR724X_PCI_CFG_BASE    0x14000000
74  #define AR724X_PCI_CFG_SIZE    0x1000
75 +#define AR724X_PCI_CTRL_BASE   (AR71XX_APB_BASE + 0x000f0000)
76 +#define AR724X_PCI_CTRL_SIZE   0x100
77 +
78  #define AR724X_PCI_MEM_BASE    0x10000000
79  #define AR724X_PCI_MEM_SIZE    0x08000000
80  
81 +#define AR724X_PCI_REG_INT_STATUS      0x4c
82 +#define AR724X_PCI_REG_INT_MASK                0x50
83 +
84 +#define AR724X_PCI_INT_DEV0            BIT(14)
85 +
86 +#define AR724X_PCI_IRQ_COUNT           1
87 +
88  #define AR7240_BAR0_WAR_VALUE  0xffff
89  
90  static DEFINE_SPINLOCK(ar724x_pci_lock);
91  static void __iomem *ar724x_pci_devcfg_base;
92 +static void __iomem *ar724x_pci_ctrl_base;
93  
94  static u32 ar724x_pci_bar0_value;
95  static bool ar724x_pci_bar0_is_cached;
96 @@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_
97         .mem_resource   = &ar724x_mem_resource,
98  };
99  
100 -int __init ar724x_pcibios_init(void)
101 +static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
102 +{
103 +       void __iomem *base;
104 +       u32 pending;
105 +
106 +       base = ar724x_pci_ctrl_base;
107 +
108 +       pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
109 +                 __raw_readl(base + AR724X_PCI_REG_INT_MASK);
110 +
111 +       if (pending & AR724X_PCI_INT_DEV0)
112 +               generic_handle_irq(ATH79_PCI_IRQ(0));
113 +
114 +       else
115 +               spurious_interrupt();
116 +}
117 +
118 +static void ar724x_pci_irq_unmask(struct irq_data *d)
119 +{
120 +       void __iomem *base;
121 +       u32 t;
122 +
123 +       base = ar724x_pci_ctrl_base;
124 +
125 +       switch (d->irq) {
126 +       case ATH79_PCI_IRQ(0):
127 +               t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
128 +               __raw_writel(t | AR724X_PCI_INT_DEV0,
129 +                            base + AR724X_PCI_REG_INT_MASK);
130 +               /* flush write */
131 +               __raw_readl(base + AR724X_PCI_REG_INT_MASK);
132 +       }
133 +}
134 +
135 +static void ar724x_pci_irq_mask(struct irq_data *d)
136 +{
137 +       void __iomem *base;
138 +       u32 t;
139 +
140 +       base = ar724x_pci_ctrl_base;
141 +
142 +       switch (d->irq) {
143 +       case ATH79_PCI_IRQ(0):
144 +               t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
145 +               __raw_writel(t & ~AR724X_PCI_INT_DEV0,
146 +                            base + AR724X_PCI_REG_INT_MASK);
147 +
148 +               /* flush write */
149 +               __raw_readl(base + AR724X_PCI_REG_INT_MASK);
150 +
151 +               t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
152 +               __raw_writel(t | AR724X_PCI_INT_DEV0,
153 +                            base + AR724X_PCI_REG_INT_STATUS);
154 +
155 +               /* flush write */
156 +               __raw_readl(base + AR724X_PCI_REG_INT_STATUS);
157 +       }
158 +}
159 +
160 +static struct irq_chip ar724x_pci_irq_chip = {
161 +       .name           = "AR724X PCI ",
162 +       .irq_mask       = ar724x_pci_irq_mask,
163 +       .irq_unmask     = ar724x_pci_irq_unmask,
164 +       .irq_mask_ack   = ar724x_pci_irq_mask,
165 +};
166 +
167 +static void __init ar724x_pci_irq_init(int irq)
168 +{
169 +       void __iomem *base;
170 +       int i;
171 +
172 +       base = ar724x_pci_ctrl_base;
173 +
174 +       __raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
175 +       __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
176 +
177 +       BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT);
178 +
179 +       for (i = ATH79_PCI_IRQ_BASE;
180 +            i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++)
181 +               irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
182 +                                        handle_level_irq);
183 +
184 +       irq_set_chained_handler(irq, ar724x_pci_irq_handler);
185 +}
186 +
187 +int __init ar724x_pcibios_init(int irq)
188  {
189 +       int ret;
190 +
191 +       ret = -ENOMEM;
192 +
193         ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE,
194                                          AR724X_PCI_CFG_SIZE);
195         if (ar724x_pci_devcfg_base == NULL)
196 -               return -ENOMEM;
197 +               goto err;
198  
199 +       ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE,
200 +                                      AR724X_PCI_CTRL_SIZE);
201 +       if (ar724x_pci_ctrl_base == NULL)
202 +               goto err_unmap_devcfg;
203 +
204 +       ar724x_pci_irq_init(irq);
205         register_pci_controller(&ar724x_pci_controller);
206  
207         return PCIBIOS_SUCCESSFUL;
208 +
209 +err_unmap_devcfg:
210 +       iounmap(ar724x_pci_devcfg_base);
211 +err:
212 +       return ret;
213  }