2 * Moschip MCS8140 PCI support
4 * Copyright (C) 2003 Moschip Semiconductors Ltd.
5 * Copyright (C) 2003 Artec Design Ltd.
6 * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org>
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.
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>
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>
33 #define MCS8140_PCI_CONFIG_SIZE SZ_64M
34 #define MCS8140_PCI_IOMISC_SIZE SZ_64M
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
41 #define MCS8140_PCI_CFG_BASE (MCS8140_PCI_HOST_BASE + 0x04000000)
42 #define MCS8140_PCI_IO_BASE (MCS8140_PCI_HOST_BASE)
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)
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
53 #define MCS8140_PCI_DEVICE_ID 0xA0009710
54 #define MCS8140_PCI_CLASS_ID 0x02000011 /* Host-Class id :0x0600 */
55 #define PCI_IF_CONFIG 0x200
57 static void __iomem
*mcs8140_pci_master_base
;
58 static void __iomem
*mcs8140_eeprom_emu_base
;
60 static unsigned long __pci_addr(struct pci_bus
*bus
,
61 unsigned int devfn
, int offset
)
63 unsigned int busnr
= bus
->number
;
66 /* we only support bus 0 */
71 * Trap out illegal values
73 BUG_ON(devfn
> 255 || busnr
> 255 || devfn
> 255);
76 slot
= PCI_SLOT(devfn
);
81 if (PCI_FUNC(devfn
) >= 4)
84 return MCS8140_PCI_CFG_VIRT_BASE
| (PCI_SLOT(devfn
) << 11) |
85 (PCI_FUNC(devfn
) << 8) | offset
;
87 pr_warn("Ignoring: PCI Slot is %x\n", PCI_SLOT(devfn
));
92 static int mcs8140_pci_host_status(void)
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
);
102 readl_relaxed(mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
109 static int mcs8140_pci_read_config(struct pci_bus
*bus
,
110 unsigned int devfn
, int where
,
113 unsigned long v
= 0xFFFFFFFF;
114 unsigned long addr
= __pci_addr(bus
, devfn
, where
);
119 v
= readb_relaxed(addr
);
123 v
= readw_relaxed(addr
);
127 v
= readl_relaxed(addr
);
133 if (mcs8140_pci_host_status())
138 return PCIBIOS_SUCCESSFUL
;
141 static void mcs8140_eeprom_emu_init(void)
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
);
149 static int mcs8140_pci_write_config(struct pci_bus
*bus
,
150 unsigned int devfn
, int where
,
153 unsigned long addr
= __pci_addr(bus
, devfn
, where
);
158 writeb_relaxed((u8
)val
, addr
);
161 writew_relaxed((u16
)val
, addr
);
164 writel_relaxed(val
, addr
);
169 return PCIBIOS_SUCCESSFUL
;
172 static struct pci_ops pci_mcs8140_ops
= {
173 .read
= mcs8140_pci_read_config
,
174 .write
= mcs8140_pci_write_config
,
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
,
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
,
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
,
199 int __init
pci_mcs8140_setup_resources(struct pci_sys_data
*sys
)
203 ret
= request_resource(&iomem_resource
, &io_mem
);
205 pr_err("PCI: unable to allocate I/O "
206 "memory region (%d)\n", ret
);
210 ret
= request_resource(&iomem_resource
, &non_mem
);
212 pr_err("PCI: unable to allocate non-prefetchable "
213 "memory region (%d)\n", ret
);
217 ret
= request_resource(&iomem_resource
, &pre_mem
);
219 pr_err("PCI: unable to allocate prefetchable "
220 "memory region (%d)\n", ret
);
221 goto release_non_mem
;
224 mcs8140_eeprom_emu_init();
226 pci_add_resource(&sys
->resources
, &io_mem
);
227 pci_add_resource(&sys
->resources
, &non_mem
);
228 pci_add_resource(&sys
->resources
, &pre_mem
);
233 release_resource(&non_mem
);
235 release_resource(&io_mem
);
240 struct pci_bus
*pci_mcs8140_scan_bus(int nr
, struct pci_sys_data
*sys
)
242 return pci_scan_bus(sys
->busnr
, &pci_mcs8140_ops
, sys
);
246 int __init
pci_mcs8140_setup(int nr
, struct pci_sys_data
*sys
)
254 sys
->mem_offset
= MCS8140_PCI_IO_VIRT_BASE
- MCS8140_PCI_IO_BASE
;
257 ret
= pci_mcs8140_setup_resources(sys
);
259 pr_err("unable to setup mcs8140 resources\n");
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
);
270 pr_info("MCS8140 PCI core found\n");
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
);
283 static int __init
mcs8140_map_irq(const struct pci_dev
*dev
, u8 slot
, u8 pin
)
285 int line
= IRQ_PCI_INTA
;
290 line
= IRQ_PCI_INTA
+ pin
; /* IRQ_PCIA - 22 */
292 line
= IRQ_PCI_INTA
+ pin
- 1; /* IRQ_PCIA - 22 */
295 pr_info("PCI: Map interrupt slot 0x%02x pin 0x%02x line 0x%02x\n",
301 static irqreturn_t
mcs8140_pci_abort_interrupt(int irq
, void *dummy
)
305 word
= readl_relaxed(mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
306 if (!(word
& (1 << 24)))
309 writel_relaxed(word
& 0xfffffff0,
310 mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
312 word
= readl_relaxed(mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
317 static int mcs8140_pci_abort_irq_init(int irq
)
321 /* Enable Interrupt in PCI Master Core */
322 word
= readl_relaxed(mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
324 writel_relaxed(word
, mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
327 word
= readl_relaxed(mcs8140_pci_master_base
+ PCI_IF_CONFIG
);
329 return request_irq(irq
, mcs8140_pci_abort_interrupt
, 0,
333 static int mcs8140_pci_host_abort(unsigned long addr
,
334 unsigned int fsr
, struct pt_regs
*regs
)
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
);
341 * If it was an imprecise abort, then we need to correct the
342 * return address to be _after_ the instruction.
344 if (fsr
& (1 << 10) || mcs8140_pci_host_status())
350 static void mcs8140_data_abort_init(void)
352 hook_fault_code(EXTERNAL_ABORT_NON_LINE_FETCH
,
353 mcs8140_pci_host_abort
, SIGBUS
,
354 0, "external abort on non-line fetch");
357 static struct hw_pci mcs8140_pci __initdata
= {
358 .map_irq
= mcs8140_map_irq
,
360 .setup
= pci_mcs8140_setup
,
361 .scan
= pci_mcs8140_scan_bus
,
364 static struct map_desc mcs8140_pci_io_desc
[] __initdata
= {
366 .virtual = MCS8140_PCI_CFG_VIRT_BASE
,
367 .pfn
= __phys_to_pfn(MCS8140_PCI_CFG_BASE
),
368 .length
= MCS8140_PCI_CONFIG_SIZE
,
372 .virtual = MCS8140_PCI_IO_VIRT_BASE
,
373 .pfn
= __phys_to_pfn(MCS8140_PCI_IO_BASE
),
374 .length
= MCS8140_PCI_IOMISC_SIZE
,
379 static int __devinit
mcs8140_pci_probe(struct platform_device
*pdev
)
381 struct resource
*res
;
384 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
386 dev_err(&pdev
->dev
, "failed to get mem resource 0\n");
390 mcs8140_pci_master_base
= devm_ioremap(&pdev
->dev
, res
->start
,
392 if (!mcs8140_pci_master_base
) {
393 dev_err(&pdev
->dev
, "failed to remap PCI master regs\n");
397 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
399 dev_err(&pdev
->dev
, "failed to get mem resource 1\n");
403 mcs8140_eeprom_emu_base
= devm_ioremap(&pdev
->dev
, res
->start
,
405 if (!mcs8140_eeprom_emu_base
) {
406 dev_err(&pdev
->dev
, "failed to remap EEPROM regs\n");
410 irq
= platform_get_irq(pdev
, 0);
412 dev_err(&pdev
->dev
, "failed to get pci abort irq\n");
416 /* Setup static mappins for PCI CFG space */
417 iotable_init(mcs8140_pci_io_desc
, ARRAY_SIZE(mcs8140_pci_io_desc
));
419 pcibios_min_io
= MCS8140_PCI_HOST_BASE
;
420 pcibios_min_mem
= MCS8140_PCI_HOST_BASE
+ MCS8140_PCI_PRE_BASE
;
422 mcs8140_data_abort_init();
423 ret
= mcs8140_pci_abort_irq_init(irq
);
425 dev_err(&pdev
->dev
, "failed to setup abort irq\n");
429 pci_common_init(&mcs8140_pci
);
434 static struct of_device_id mcs8140_of_ids
[] __devinitdata
= {
435 { .compatible
= "moschip,mcs8140-pci" },
436 { .compatible
= "moschip,mcs814x-pci" },
440 static struct platform_driver mcs8140_pci_driver
= {
442 .name
= "mcs8140-pci",
443 .of_match_table
= mcs8140_of_ids
,
445 .probe
= mcs8140_pci_probe
,
448 static int __init
mcs8140_pci_init(void)
450 return platform_driver_register(&mcs8140_pci_driver
);
452 subsys_initcall(mcs8140_pci_init
);