rpcd: iwinfo plugin fixes
[openwrt.git] / target / linux / gemini / patches-4.1 / 140-arm-gemini-add-pci-support.patch
1 --- a/arch/arm/Kconfig
2 +++ b/arch/arm/Kconfig
3 @@ -381,6 +381,7 @@ config ARCH_GEMINI
4         select CLKSRC_MMIO
5         select CPU_FA526
6         select GENERIC_CLOCKEVENTS
7 +       select MIGHT_HAVE_PCI
8         help
9           Support for the Cortina Systems Gemini family SoCs
10  
11 --- a/arch/arm/mach-gemini/include/mach/hardware.h
12 +++ b/arch/arm/mach-gemini/include/mach/hardware.h
13 @@ -71,4 +71,9 @@
14   */
15  #define IO_ADDRESS(x)  IOMEM((((x) & 0xFFF00000) >> 4) | ((x) & 0x000FFFFF) | 0xF0000000)
16  
17 +/*
18 + * PCI subsystem macros
19 + */
20 +#define pcibios_assign_all_busses()    1
21 +
22  #endif
23 --- a/arch/arm/mach-gemini/include/mach/irqs.h
24 +++ b/arch/arm/mach-gemini/include/mach/irqs.h
25 @@ -43,11 +43,14 @@
26  
27  #define NORMAL_IRQ_NUM 32
28  
29 -#define GPIO_IRQ_BASE  NORMAL_IRQ_NUM
30 +#define PCI_IRQ_BASE   NORMAL_IRQ_NUM
31 +#define PCI_IRQ_NUM    4
32 +
33 +#define GPIO_IRQ_BASE  (NORMAL_IRQ_NUM + PCI_IRQ_NUM)
34  #define GPIO_IRQ_NUM   (3 * 32)
35  
36  #define ARCH_TIMER_IRQ IRQ_TIMER2
37  
38 -#define NR_IRQS                (NORMAL_IRQ_NUM + GPIO_IRQ_NUM)
39 +#define NR_IRQS                (NORMAL_IRQ_NUM + PCI_IRQ_NUM + GPIO_IRQ_NUM)
40  
41  #endif /* __MACH_IRQS_H__ */
42 --- a/arch/arm/mach-gemini/Makefile
43 +++ b/arch/arm/mach-gemini/Makefile
44 @@ -6,6 +6,8 @@
45  
46  obj-y                  := irq.o mm.o time.o devices.o gpio.o idle.o reset.o
47  
48 +obj-$(CONFIG_PCI)      += pci.o
49 +
50  # Board-specific support
51  obj-$(CONFIG_MACH_NAS4220B)    += board-nas4220b.o
52  obj-$(CONFIG_MACH_RUT100)      += board-rut1xx.o
53 --- a/arch/arm/mach-gemini/mm.c
54 +++ b/arch/arm/mach-gemini/mm.c
55 @@ -59,6 +59,11 @@ static struct map_desc gemini_io_desc[]
56                 .length         = SZ_512K,
57                 .type           = MT_DEVICE,
58         }, {
59 +               .virtual        = (unsigned long)IO_ADDRESS(GEMINI_PCI_IO_BASE),
60 +               .pfn            = __phys_to_pfn(GEMINI_PCI_IO_BASE),
61 +               .length         = SZ_512K,
62 +               .type           = MT_DEVICE,
63 +       }, {
64                 .virtual        = (unsigned long)IO_ADDRESS(GEMINI_FLASH_CTRL_BASE),
65                 .pfn            = __phys_to_pfn(GEMINI_FLASH_CTRL_BASE),
66                 .length         = SZ_512K,
67 --- /dev/null
68 +++ b/arch/arm/mach-gemini/pci.c
69 @@ -0,0 +1,320 @@
70 +/*
71 + *  Support for Gemini PCI Controller
72 + *
73 + *  Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
74 + *  Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
75 + *
76 + * based on SL2312 PCI controller code
77 + *   Storlink (C) 2003
78 + *
79 + * This program is free software; you can redistribute it and/or modify
80 + * it under the terms of the GNU General Public License as published by
81 + * the Free Software Foundation; either version 2 of the License, or
82 + * (at your option) any later version.
83 + */
84 +
85 +#include <linux/kernel.h>
86 +#include <linux/pci.h>
87 +#include <linux/irq.h>
88 +#include <linux/gpio.h>
89 +
90 +#include <asm/mach/pci.h>
91 +
92 +#include <mach/irqs.h>
93 +#include <mach/hardware.h>
94 +
95 +#define GEMINI_PCI_IOSIZE_1M           0x0000
96 +
97 +#define GEMINI_PCI_PMC                 0x40
98 +#define GEMINI_PCI_PMCSR               0x44
99 +#define GEMINI_PCI_CTRL1               0x48
100 +#define GEMINI_PCI_CTRL2               0x4C
101 +#define GEMINI_PCI_MEM1_BASE_SIZE      0x50
102 +#define GEMINI_PCI_MEM2_BASE_SIZE      0x54
103 +#define GEMINI_PCI_MEM3_BASE_SIZE      0x58
104 +
105 +#define PCI_CTRL2_INTSTS_OFFSET                28
106 +#define PCI_CTRL2_INTMASK_OFFSET       22
107 +
108 +#define GEMINI_PCI_DMA_MASK            0xFFF00000
109 +#define GEMINI_PCI_DMA_MEM1_BASE       0x00000000
110 +#define GEMINI_PCI_DMA_MEM2_BASE       0x00000000
111 +#define GEMINI_PCI_DMA_MEM3_BASE       0x00000000
112 +#define GEMINI_PCI_DMA_MEM1_SIZE       7
113 +#define GEMINI_PCI_DMA_MEM2_SIZE       6
114 +#define GEMINI_PCI_DMA_MEM3_SIZE       6
115 +
116 +#define PCI_CONF_ENABLE                (1 << 31)
117 +#define PCI_CONF_WHERE(r)      ((r) & 0xFC)
118 +#define PCI_CONF_BUS(b)                (((b) & 0xFF) << 16)
119 +#define PCI_CONF_DEVICE(d)     (((d) & 0x1F) << 11)
120 +#define PCI_CONF_FUNCTION(f)   (((f) & 0x07) << 8)
121 +
122 +#define PCI_IOSIZE_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE))
123 +#define PCI_PROT_REG   (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x04)
124 +#define PCI_CTRL_REG   (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x08)
125 +#define PCI_SOFTRST_REG        (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x10)
126 +#define PCI_CONFIG_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x28)
127 +#define PCI_DATA_REG   (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x2C)
128 +
129 +
130 +static DEFINE_SPINLOCK(gemini_pci_lock);
131 +
132 +static int gemini_pci_read_config(struct pci_bus* bus, unsigned int fn,
133 +                                 int config, int size, u32* value)
134 +{
135 +       unsigned long irq_flags;
136 +
137 +       spin_lock_irqsave(&gemini_pci_lock, irq_flags);
138 +
139 +       __raw_writel(PCI_CONF_BUS(bus->number) |
140 +                       PCI_CONF_DEVICE(PCI_SLOT(fn)) |
141 +                       PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
142 +                       PCI_CONF_WHERE(config) |
143 +                       PCI_CONF_ENABLE,
144 +                       PCI_CONFIG_REG);
145 +
146 +       *value = __raw_readl(PCI_DATA_REG);
147 +
148 +       if (size == 1)
149 +               *value = (*value >> (8 * (config & 3))) & 0xFF;
150 +       else if (size == 2)
151 +               *value = (*value >> (8 * (config & 3))) & 0xFFFF;
152 +
153 +       spin_unlock_irqrestore(&gemini_pci_lock, irq_flags);
154 +
155 +       dev_dbg(&bus->dev,
156 +               "[read]  slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n",
157 +               PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value);
158 +
159 +       return PCIBIOS_SUCCESSFUL;
160 +}
161 +
162 +static int gemini_pci_write_config(struct pci_bus* bus, unsigned int fn,
163 +                                  int config, int size, u32 value)
164 +{
165 +       unsigned long irq_flags = 0;
166 +       int ret = PCIBIOS_SUCCESSFUL;
167 +
168 +       dev_dbg(&bus->dev,
169 +               "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n",
170 +               PCI_SLOT(fn), PCI_FUNC(fn), config, size, value);
171 +
172 +       spin_lock_irqsave(&gemini_pci_lock, irq_flags);
173 +
174 +       __raw_writel(PCI_CONF_BUS(bus->number) |
175 +                       PCI_CONF_DEVICE(PCI_SLOT(fn)) |
176 +                       PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
177 +                       PCI_CONF_WHERE(config) |
178 +                       PCI_CONF_ENABLE,
179 +                       PCI_CONFIG_REG);
180 +
181 +       switch(size) {
182 +       case 4:
183 +               __raw_writel(value, PCI_DATA_REG);
184 +               break;
185 +       case 2:
186 +               __raw_writew(value, PCI_DATA_REG + (config & 3));
187 +               break;
188 +       case 1:
189 +               __raw_writeb(value, PCI_DATA_REG + (config & 3));
190 +               break;
191 +       default:
192 +               ret = PCIBIOS_BAD_REGISTER_NUMBER;
193 +       }
194 +
195 +       spin_unlock_irqrestore(&gemini_pci_lock, irq_flags);
196 +
197 +       return ret;
198 +}
199 +
200 +static struct pci_ops gemini_pci_ops = {
201 +       .read   = gemini_pci_read_config,
202 +       .write  = gemini_pci_write_config,
203 +};
204 +
205 +static struct resource gemini_pci_resource_io = {
206 +       .name   = "PCI I/O Space",
207 +       .start  = GEMINI_PCI_IO_BASE,
208 +       .end    = GEMINI_PCI_IO_BASE + SZ_1M - 1,
209 +       .flags  = IORESOURCE_IO,
210 +};
211 +
212 +static struct resource gemini_pci_resource_mem = {
213 +       .name   = "PCI Memory Space",
214 +       .start  = GEMINI_PCI_MEM_BASE,
215 +       .end    = GEMINI_PCI_MEM_BASE + SZ_128M - 1,
216 +       .flags  = IORESOURCE_MEM,
217 +};
218 +
219 +static int __init gemini_pci_request_resources(struct pci_sys_data *sys)
220 +{
221 +       if (request_resource(&ioport_resource, &gemini_pci_resource_io))
222 +               goto bad_resources;
223 +       if (request_resource(&iomem_resource, &gemini_pci_resource_mem))
224 +               goto bad_resources;
225 +
226 +       pci_add_resource(&sys->resources, &gemini_pci_resource_io);
227 +       pci_add_resource(&sys->resources, &gemini_pci_resource_mem);
228 +
229 +       return 0;
230 +
231 +bad_resources:
232 +       pr_err("Gemini PCI: request_resource() failed. "
233 +                       "Abort PCI bus enumeration.\n");
234 +       return -1;
235 +}
236 +
237 +static int __init gemini_pci_setup(int nr, struct pci_sys_data *sys)
238 +{
239 +       unsigned int cmd;
240 +
241 +       pcibios_min_io = 0x100;
242 +       pcibios_min_mem = 0;
243 +
244 +       if ((nr > 0) || gemini_pci_request_resources(sys))
245 +               return 0;
246 +
247 +       /* setup I/O space to 1MB size */
248 +       __raw_writel(GEMINI_PCI_IOSIZE_1M, PCI_IOSIZE_REG);
249 +
250 +       /* setup hostbridge */
251 +       cmd = __raw_readl(PCI_CTRL_REG);
252 +       cmd |= PCI_COMMAND_IO;
253 +       cmd |= PCI_COMMAND_MEMORY;
254 +       cmd |= PCI_COMMAND_MASTER;
255 +       __raw_writel(cmd, PCI_CTRL_REG);
256 +
257 +       return 1;
258 +}
259 +
260 +static struct pci_bus* __init gemini_pci_scan_bus(int nr, struct pci_sys_data* sys)
261 +{
262 +       unsigned int reg = 0;
263 +       struct pci_bus* bus = 0;
264 +
265 +       bus = pci_scan_bus(nr, &gemini_pci_ops, sys);
266 +       if (bus) {
267 +               dev_dbg(&bus->dev, "setting up PCI DMA\n");
268 +               reg = (GEMINI_PCI_DMA_MEM1_BASE & GEMINI_PCI_DMA_MASK)
269 +                       | (GEMINI_PCI_DMA_MEM1_SIZE << 16);
270 +               gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM1_BASE_SIZE, 4, reg);
271 +               reg =   (GEMINI_PCI_DMA_MEM2_BASE & GEMINI_PCI_DMA_MASK)
272 +                       | (GEMINI_PCI_DMA_MEM2_SIZE << 16);
273 +               gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM2_BASE_SIZE, 4, reg);
274 +               reg = (GEMINI_PCI_DMA_MEM3_BASE & GEMINI_PCI_DMA_MASK)
275 +                       | (GEMINI_PCI_DMA_MEM3_SIZE << 16);
276 +               gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM3_BASE_SIZE, 4, reg);
277 +       }
278 +
279 +       return bus;
280 +}
281 +
282 +/* Should work with all boards based on original Storlink EVB */
283 +static int __init gemini_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
284 +{
285 +       if (slot < 9 || slot > 12)
286 +               return -1;
287 +
288 +       return PCI_IRQ_BASE + (((slot - 9) + (pin - 1)) & 0x3);
289 +}
290 +
291 +static struct hw_pci gemini_hw_pci __initdata = {
292 +       .nr_controllers = 1,
293 +       .setup          = gemini_pci_setup,
294 +       .scan           = gemini_pci_scan_bus,
295 +       .map_irq        = gemini_pci_map_irq,
296 +};
297 +
298 +/* we need this for muxed PCI interrupts handling */
299 +static struct pci_bus bogus_pci_bus;
300 +
301 +static void gemini_pci_ack_irq(struct irq_data *d)
302 +{
303 +       unsigned int irq = d->irq;
304 +       unsigned int reg;
305 +
306 +       gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
307 +       reg &= ~(0xF << PCI_CTRL2_INTSTS_OFFSET);
308 +       reg |= 1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTSTS_OFFSET);
309 +       gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg);
310 +}
311 +
312 +static void gemini_pci_mask_irq(struct irq_data *d)
313 +{
314 +       unsigned int irq = d->irq;
315 +       unsigned int reg;
316 +
317 +       gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
318 +       reg &= ~((0xF << PCI_CTRL2_INTSTS_OFFSET)
319 +               | (1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTMASK_OFFSET)));
320 +       gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg);
321 +}
322 +
323 +static void gemini_pci_unmask_irq(struct irq_data *d)
324 +{
325 +       unsigned int irq = d->irq;
326 +       unsigned int reg;
327 +
328 +       gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
329 +       reg &= ~(0xF << PCI_CTRL2_INTSTS_OFFSET);
330 +       reg |= 1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTMASK_OFFSET);
331 +       gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg);
332 +}
333 +
334 +static void gemini_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
335 +{
336 +       unsigned int pci_irq_no, irq_stat, reg, i;
337 +
338 +       gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, &reg);
339 +       irq_stat = reg >> PCI_CTRL2_INTSTS_OFFSET;
340 +
341 +       for (i = 0; i < 4; i++) {
342 +
343 +               if ((irq_stat & (1 << i)) == 0)
344 +                       continue;
345 +
346 +               pci_irq_no = PCI_IRQ_BASE + i;
347 +
348 +               BUG_ON(!(irq_desc[pci_irq_no].handle_irq));
349 +               irq_desc[pci_irq_no].handle_irq(pci_irq_no,
350 +                               &irq_desc[pci_irq_no]);
351 +       }
352 +}
353 +
354 +static struct irq_chip gemini_pci_irq_chip = {
355 +       .name = "PCI",
356 +       .irq_ack = gemini_pci_ack_irq,
357 +       .irq_mask = gemini_pci_mask_irq,
358 +       .irq_unmask = gemini_pci_unmask_irq,
359 +};
360 +
361 +static int __init gemini_pci_init(void)
362 +{
363 +       int i;
364 +
365 +       for (i = 72; i <= 95; i++)
366 +               gpio_request(i, "PCI");
367 +
368 +       /* initialize our bogus bus */
369 +       dev_set_name(&bogus_pci_bus.dev, "PCI IRQ handler");
370 +       bogus_pci_bus.number = 0;
371 +
372 +       /* mask and clear all interrupts */
373 +       gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2 + 2, 2,
374 +                               0xF000);
375 +
376 +       for (i = PCI_IRQ_BASE; i < PCI_IRQ_BASE + 4; i++) {
377 +               irq_set_chip_and_handler(i, &gemini_pci_irq_chip,
378 +                                        handle_level_irq);
379 +               set_irq_flags(i, IRQF_VALID);
380 +       }
381 +
382 +       irq_set_chained_handler(IRQ_PCI, gemini_pci_irq_handler);
383 +
384 +       pci_common_init(&gemini_hw_pci);
385 +
386 +       return 0;
387 +}
388 +
389 +subsys_initcall(gemini_pci_init);