3606fe84e41c42b534ecd845656fd18ddee7b12f
[openwrt.git] / target / linux / mcs814x / files-3.3 / arch / arm / mach-mcs814x / pci.c
1 /*
2  * Moschip MCS8140 PCI support
3  *
4  * Copyright (C) 2003 Moschip Semiconductors Ltd.
5  * Copyright (C) 2003 Artec Design Ltd.
6  * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/pci.h>
16 #include <linux/ptrace.h>
17 #include <linux/slab.h>
18 #include <linux/ioport.h>
19 #include <linux/interrupt.h>
20 #include <linux/spinlock.h>
21 #include <linux/init.h>
22 #include <linux/platform_device.h>
23 #include <linux/of.h>
24 #include <linux/io.h>
25
26 #include <asm/irq.h>
27 #include <asm/system.h>
28 #include <asm/mach/pci.h>
29 #include <asm/mach/map.h>
30 #include <mach/mcs814x.h>
31 #include <mach/irqs.h>
32
33 #define MCS8140_PCI_CONFIG_SIZE         SZ_64M
34 #define MCS8140_PCI_IOMISC_SIZE         SZ_64M
35
36 #define MCS8140_PCI_HOST_BASE           0x80000000
37 #define MCS8140_PCI_IOMISC_BASE         0x00000000
38 #define MCS8140_PCI_PRE_BASE            0x10000000
39 #define MCS8140_PCI_NONPRE_BASE         0x30000000
40
41 #define MCS8140_PCI_CFG_BASE            (MCS8140_PCI_HOST_BASE + 0x04000000)
42 #define MCS8140_PCI_IO_BASE             (MCS8140_PCI_HOST_BASE)
43
44 #define MCS8140_PCI_IO_VIRT_BASE        (MCS814X_IO_BASE - MCS8140_PCI_CONFIG_SIZE - \
45                                          MCS8140_PCI_IOMISC_SIZE)
46 #define MCS8140_PCI_CFG_VIRT_BASE       (MCS814X_IO_BASE - MCS8140_PCI_CONFIG_SIZE)
47
48 #define PCI_FATAL_ERROR                 1
49 #define EXTERNAL_ABORT_NON_LINE_FETCH   8
50 #define EPRM_DONE                       0x80
51 #define EPRM_SDRAM_FUNC0                0xAC
52 #define PCI_INTD                        4
53 #define MCS8140_PCI_DEVICE_ID           0xA0009710
54 #define MCS8140_PCI_CLASS_ID            0x02000011  /* Host-Class id :0x0600 */
55 #define PCI_IF_CONFIG                   0x200
56
57 static void __iomem *mcs8140_pci_master_base;
58 static void __iomem *mcs8140_eeprom_emu_base;
59
60 static unsigned long __pci_addr(struct pci_bus *bus,
61                                 unsigned int devfn, int offset)
62 {
63         unsigned int busnr = bus->number;
64         unsigned int slot;
65
66         /* we only support bus 0 */
67         if (busnr != 0)
68                 return 0;
69
70         /*
71          * Trap out illegal values
72          */
73         BUG_ON(devfn > 255 || busnr > 255 || devfn > 255);
74
75         /* Scan 3 slots */
76         slot = PCI_SLOT(devfn);
77         switch (slot) {
78         case 1:
79         case 2:
80         case 3:
81                 if (PCI_FUNC(devfn) >= 4)
82                         return 0;
83
84                 return MCS8140_PCI_CFG_VIRT_BASE | (PCI_SLOT(devfn) << 11) |
85                         (PCI_FUNC(devfn) << 8) | offset;
86         default:
87                 pr_warn("Ignoring: PCI Slot is %x\n", PCI_SLOT(devfn));
88                 return 0;
89         }
90 }
91
92 static int mcs8140_pci_host_status(void)
93 {
94         u32 host_status;
95
96         host_status = readl_relaxed(mcs8140_pci_master_base + PCI_IF_CONFIG);
97         if (host_status & PCI_FATAL_ERROR) {
98                 writel_relaxed(host_status & 0xfffffff0,
99                         mcs8140_pci_master_base + PCI_IF_CONFIG);
100                 /* flush write */
101                 host_status =
102                         readl_relaxed(mcs8140_pci_master_base + PCI_IF_CONFIG);
103                 return 1;
104         }
105
106         return 0;
107 }
108
109 static int mcs8140_pci_read_config(struct pci_bus *bus,
110                                         unsigned int devfn, int where,
111                                         int size, u32 *val)
112 {
113         unsigned long v = 0xFFFFFFFF;
114         unsigned long addr = __pci_addr(bus, devfn, where);
115
116         if (addr != 0) {
117                 switch (size) {
118                 case 1:
119                         v = __raw_readb(addr);
120                         break;
121                 case 2:
122                         addr &= ~1;
123                         v = __raw_readw(addr);
124                         break;
125                 default:
126                         addr &= ~3;
127                         v = readl_relaxed(addr);
128                         break;
129                 }
130         } else
131                 v = 0xffffffff;
132
133         if (mcs8140_pci_host_status())
134                 v = 0xffffffff;
135
136         *val = v;
137
138         return PCIBIOS_SUCCESSFUL;
139 }
140
141 static void mcs8140_eeprom_emu_init(void)
142 {
143         writel_relaxed(0x0000000F, mcs8140_eeprom_emu_base + EPRM_SDRAM_FUNC0);
144         writel_relaxed(0x08000000, MCS8140_PCI_CFG_VIRT_BASE + 0x10);
145         /* Set the DONE bit of the EEPROM emulator */
146         writel_relaxed(0x01, mcs8140_eeprom_emu_base + EPRM_DONE);
147 }
148
149 static int mcs8140_pci_write_config(struct pci_bus *bus,
150                                         unsigned int devfn, int where,
151                                         int size, u32 val)
152 {
153         unsigned long addr = __pci_addr(bus, devfn, where);
154
155         if (addr != 0) {
156                 switch (size) {
157                 case 1:
158                         __raw_writeb((u8)val, addr);
159                         break;
160                 case 2:
161                         __raw_writew((u16)val, addr);
162                         break;
163                 case 4:
164                         writel_relaxed(val, addr);
165                         break;
166                 }
167         }
168
169         return PCIBIOS_SUCCESSFUL;
170 }
171
172 static struct pci_ops pci_mcs8140_ops = {
173         .read   = mcs8140_pci_read_config,
174         .write  = mcs8140_pci_write_config,
175 };
176
177
178 static struct resource io_mem = {
179         .name   = "PCI I/O space",
180         .start  = MCS8140_PCI_HOST_BASE + MCS8140_PCI_IOMISC_BASE,
181         .end    = MCS8140_PCI_HOST_BASE + MCS8140_PCI_IOMISC_BASE + SZ_64M,
182         .flags  = IORESOURCE_IO,
183 };
184
185 static struct resource pre_mem = {
186         .name   = "PCI prefetchable",
187         .start  = MCS8140_PCI_HOST_BASE + MCS8140_PCI_PRE_BASE,
188         .end    = MCS8140_PCI_HOST_BASE + MCS8140_PCI_PRE_BASE + SZ_512M,
189         .flags  = IORESOURCE_MEM | IORESOURCE_PREFETCH,
190 };
191
192 static struct resource non_mem = {
193         .name   = "PCI non-prefetchable",
194         .start  = MCS8140_PCI_HOST_BASE + MCS8140_PCI_NONPRE_BASE,
195         .end    = MCS8140_PCI_HOST_BASE + MCS8140_PCI_NONPRE_BASE + SZ_256M,
196         .flags  = IORESOURCE_MEM,
197 };
198
199 int __init pci_mcs8140_setup_resources(struct pci_sys_data *sys)
200 {
201         int ret = 0;
202
203         ret = request_resource(&iomem_resource, &io_mem);
204         if (ret) {
205                 pr_err("PCI: unable to allocate I/O "
206                         "memory region (%d)\n", ret);
207                 goto out;
208         }
209
210         ret = request_resource(&iomem_resource, &non_mem);
211         if (ret) {
212                 pr_err("PCI: unable to allocate non-prefetchable "
213                         "memory region (%d)\n", ret);
214                 goto release_io_mem;
215         }
216
217         ret = request_resource(&iomem_resource, &pre_mem);
218         if (ret) {
219                 pr_err("PCI: unable to allocate prefetchable "
220                         "memory region (%d)\n", ret);
221                 goto release_non_mem;
222         }
223
224         mcs8140_eeprom_emu_init();
225
226         pci_add_resource(&sys->resources, &io_mem);
227         pci_add_resource(&sys->resources, &non_mem);
228         pci_add_resource(&sys->resources, &pre_mem);
229
230         return ret;
231
232 release_non_mem:
233         release_resource(&non_mem);
234 release_io_mem:
235         release_resource(&io_mem);
236 out:
237         return ret;
238 }
239
240 struct pci_bus *pci_mcs8140_scan_bus(int nr, struct pci_sys_data *sys)
241 {
242         return pci_scan_bus(sys->busnr, &pci_mcs8140_ops, sys);
243 }
244
245
246 int __init pci_mcs8140_setup(int nr, struct pci_sys_data *sys)
247 {
248         int ret = 0;
249         u32 val;
250
251         if (nr > 0)
252                 return 0;
253
254         sys->mem_offset = MCS8140_PCI_IO_VIRT_BASE - MCS8140_PCI_IO_BASE;
255         sys->io_offset = 0;
256
257         ret = pci_mcs8140_setup_resources(sys);
258         if (ret < 0) {
259                 pr_err("unable to setup mcs8140 resources\n");
260                 goto out;
261         }
262
263         val = readl_relaxed(MCS8140_PCI_CFG_VIRT_BASE);
264         if (val != MCS8140_PCI_DEVICE_ID) {
265                 pr_err("cannot find MCS8140 PCI Core: %08x\n", val);
266                 ret = -EIO;
267                 goto out;
268         }
269
270         pr_info("MCS8140 PCI core found\n");
271
272         val = readl_relaxed(MCS8140_PCI_CFG_VIRT_BASE + PCI_COMMAND);
273         /* Added to support wireless cards */
274         writel_relaxed(0, MCS8140_PCI_CFG_VIRT_BASE + 0x40);
275         writel_relaxed(val | 0x147, MCS8140_PCI_CFG_VIRT_BASE + PCI_COMMAND);
276         val = readl_relaxed(MCS8140_PCI_CFG_VIRT_BASE + PCI_COMMAND);
277         ret = 1;
278 out:
279         return ret;
280 }
281
282
283 static int __init mcs8140_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
284 {
285         int line = IRQ_PCI_INTA;
286
287         if (pin != 0) {
288                 /* IRQ_PCIA - 22 */
289                 if (pin == PCI_INTD)
290                         line = IRQ_PCI_INTA + pin; /* IRQ_PCIA - 22 */
291                 else
292                         line = IRQ_PCI_INTA + pin - 1; /* IRQ_PCIA - 22 */
293         }
294
295         pr_info("PCI: Map interrupt slot 0x%02x pin 0x%02x line 0x%02x\n",
296                 slot, pin, line);
297
298         return line;
299 }
300
301 static irqreturn_t mcs8140_pci_abort_interrupt(int irq, void *dummy)
302 {
303         u32 word;
304
305         word = readl_relaxed(mcs8140_pci_master_base + PCI_IF_CONFIG);
306         if (!(word & (1 << 24)))
307                 return IRQ_NONE;
308
309         writel_relaxed(word & 0xfffffff0,
310                 mcs8140_pci_master_base + PCI_IF_CONFIG);
311         /* flush write */
312         word = readl_relaxed(mcs8140_pci_master_base + PCI_IF_CONFIG);
313
314         return IRQ_HANDLED;
315 }
316
317 static int mcs8140_pci_abort_irq_init(int irq)
318 {
319         u32 word;
320
321         /* Enable Interrupt in PCI Master Core */
322         word = readl_relaxed(mcs8140_pci_master_base + PCI_IF_CONFIG);
323         word |= (1 << 24);
324         writel_relaxed(word, mcs8140_pci_master_base + PCI_IF_CONFIG);
325
326         /* flush write */
327         word = readl_relaxed(mcs8140_pci_master_base + PCI_IF_CONFIG);
328
329         return request_irq(irq, mcs8140_pci_abort_interrupt, 0,
330                         "PCI abort", NULL);
331 }
332
333 static int mcs8140_pci_host_abort(unsigned long addr,
334                                 unsigned int fsr, struct pt_regs *regs)
335 {
336         pr_warn("PCI Data abort: address = 0x%08lx fsr = 0x%03x"
337                 "PC = 0x%08lx LR = 0x%08lx\n",
338                 addr, fsr, regs->ARM_pc, regs->ARM_lr);
339
340         /*
341          * If it was an imprecise abort, then we need to correct the
342          * return address to be _after_ the instruction.
343          */
344         if (fsr & (1 << 10) || mcs8140_pci_host_status())
345                 regs->ARM_pc += 4;
346
347         return 0;
348 }
349
350 static void mcs8140_data_abort_init(void)
351 {
352         hook_fault_code(EXTERNAL_ABORT_NON_LINE_FETCH,
353                 mcs8140_pci_host_abort, SIGBUS,
354                 0, "external abort on non-line fetch");
355 }
356
357 static struct hw_pci mcs8140_pci __initdata = {
358         .map_irq                = mcs8140_map_irq,
359         .nr_controllers         = 1,
360         .setup                  = pci_mcs8140_setup,
361         .scan                   = pci_mcs8140_scan_bus,
362 };
363
364 static struct map_desc mcs8140_pci_io_desc[] __initdata = {
365         {
366                 .virtual        = MCS8140_PCI_CFG_VIRT_BASE,
367                 .pfn            = __phys_to_pfn(MCS8140_PCI_CFG_BASE),
368                 .length         = MCS8140_PCI_CONFIG_SIZE,
369                 .type           = MT_DEVICE
370         },
371         {
372                 .virtual        = MCS8140_PCI_IO_VIRT_BASE,
373                 .pfn            = __phys_to_pfn(MCS8140_PCI_IO_BASE),
374                 .length         = MCS8140_PCI_IOMISC_SIZE,
375                 .type           = MT_DEVICE
376         },
377 };
378
379 static int __devinit mcs8140_pci_probe(struct platform_device *pdev)
380 {
381         struct resource *res;
382         int ret, irq;
383
384         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
385         if (!res) {
386                 dev_err(&pdev->dev, "failed to get mem resource 0\n");
387                 return -ENODEV;
388         }
389
390         mcs8140_pci_master_base = devm_ioremap(&pdev->dev, res->start,
391                                         resource_size(res));
392         if (!mcs8140_pci_master_base) {
393                 dev_err(&pdev->dev, "failed to remap PCI master regs\n");
394                 return -ENODEV;
395         }
396
397         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
398         if (!res) {
399                 dev_err(&pdev->dev, "failed to get mem resource 1\n");
400                 return -ENOMEM;
401         }
402
403         mcs8140_eeprom_emu_base = devm_ioremap(&pdev->dev, res->start,
404                                         resource_size(res));
405         if (!mcs8140_eeprom_emu_base) {
406                 dev_err(&pdev->dev, "failed to remap EEPROM regs\n");
407                 return -ENOMEM;
408         }
409
410         irq = platform_get_irq(pdev, 0);
411         if (irq < 0) {
412                 dev_err(&pdev->dev, "failed to get pci abort irq\n");
413                 return -ENODEV;
414         }
415
416         /* Setup static mappins for PCI CFG space */
417         iotable_init(mcs8140_pci_io_desc, ARRAY_SIZE(mcs8140_pci_io_desc));
418
419         pcibios_min_io = MCS8140_PCI_HOST_BASE;
420         pcibios_min_mem = MCS8140_PCI_HOST_BASE + MCS8140_PCI_PRE_BASE;
421
422         mcs8140_data_abort_init();
423         ret = mcs8140_pci_abort_irq_init(irq);
424         if (ret) {
425                 dev_err(&pdev->dev, "failed to setup abort irq\n");
426                 return ret;
427         }
428
429         pci_common_init(&mcs8140_pci);
430
431         return 0;
432 }
433
434 static struct of_device_id mcs8140_of_ids[] __devinitdata = {
435         { .compatible = "moschip,mcs8140-pci" },
436         { .compatible = "moschip,mcs814x-pci" },
437         { /* sentinel */ },
438 };
439
440 static struct platform_driver mcs8140_pci_driver = {
441         .driver = {
442                 .name   = "mcs8140-pci",
443                 .of_match_table = mcs8140_of_ids,
444         },
445         .probe  = mcs8140_pci_probe,
446 };
447
448 static int __init mcs8140_pci_init(void)
449 {
450         return platform_driver_register(&mcs8140_pci_driver);
451 }
452 subsys_initcall(mcs8140_pci_init);
453