diff options
Diffstat (limited to 'arch/powerpc/platforms/86xx/pci.c')
-rw-r--r-- | arch/powerpc/platforms/86xx/pci.c | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c new file mode 100644 index 000000000000..5180df7c75bc --- /dev/null +++ b/arch/powerpc/platforms/86xx/pci.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | * MPC86XX pci setup code | ||
3 | * | ||
4 | * Recode: ZHANG WEI <wei.zhang@freescale.com> | ||
5 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> | ||
6 | * | ||
7 | * Copyright 2006 Freescale Semiconductor Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/serial.h> | ||
21 | |||
22 | #include <asm/system.h> | ||
23 | #include <asm/atomic.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/prom.h> | ||
26 | #include <asm/immap_86xx.h> | ||
27 | #include <asm/pci-bridge.h> | ||
28 | #include <sysdev/fsl_soc.h> | ||
29 | |||
30 | #include "mpc86xx.h" | ||
31 | |||
32 | #undef DEBUG | ||
33 | |||
34 | #ifdef DEBUG | ||
35 | #define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) | ||
36 | #else | ||
37 | #define DBG(fmt, args...) | ||
38 | #endif | ||
39 | |||
40 | struct pcie_outbound_window_regs { | ||
41 | uint pexotar; /* 0x.0 - PCI Express outbound translation address register */ | ||
42 | uint pexotear; /* 0x.4 - PCI Express outbound translation extended address register */ | ||
43 | uint pexowbar; /* 0x.8 - PCI Express outbound window base address register */ | ||
44 | char res1[4]; | ||
45 | uint pexowar; /* 0x.10 - PCI Express outbound window attributes register */ | ||
46 | char res2[12]; | ||
47 | }; | ||
48 | |||
49 | struct pcie_inbound_window_regs { | ||
50 | uint pexitar; /* 0x.0 - PCI Express inbound translation address register */ | ||
51 | char res1[4]; | ||
52 | uint pexiwbar; /* 0x.8 - PCI Express inbound window base address register */ | ||
53 | uint pexiwbear; /* 0x.c - PCI Express inbound window base extended address register */ | ||
54 | uint pexiwar; /* 0x.10 - PCI Express inbound window attributes register */ | ||
55 | char res2[12]; | ||
56 | }; | ||
57 | |||
58 | static void __init setup_pcie_atmu(struct pci_controller *hose, struct resource *rsrc) | ||
59 | { | ||
60 | volatile struct ccsr_pex *pcie; | ||
61 | volatile struct pcie_outbound_window_regs *pcieow; | ||
62 | volatile struct pcie_inbound_window_regs *pcieiw; | ||
63 | int i = 0; | ||
64 | |||
65 | DBG("PCIE memory map start 0x%x, size 0x%x\n", rsrc->start, | ||
66 | rsrc->end - rsrc->start + 1); | ||
67 | pcie = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); | ||
68 | |||
69 | /* Disable all windows (except pexowar0 since its ignored) */ | ||
70 | pcie->pexowar1 = 0; | ||
71 | pcie->pexowar2 = 0; | ||
72 | pcie->pexowar3 = 0; | ||
73 | pcie->pexowar4 = 0; | ||
74 | pcie->pexiwar1 = 0; | ||
75 | pcie->pexiwar2 = 0; | ||
76 | pcie->pexiwar3 = 0; | ||
77 | |||
78 | pcieow = (struct pcie_outbound_window_regs *)&pcie->pexotar1; | ||
79 | pcieiw = (struct pcie_inbound_window_regs *)&pcie->pexitar1; | ||
80 | |||
81 | /* Setup outbound MEM window */ | ||
82 | for(i = 0; i < 3; i++) | ||
83 | if (hose->mem_resources[i].flags & IORESOURCE_MEM){ | ||
84 | DBG("PCIE MEM resource start 0x%08x, size 0x%08x.\n", | ||
85 | hose->mem_resources[i].start, | ||
86 | hose->mem_resources[i].end | ||
87 | - hose->mem_resources[i].start + 1); | ||
88 | pcieow->pexotar = (hose->mem_resources[i].start) >> 12 | ||
89 | & 0x000fffff; | ||
90 | pcieow->pexotear = 0; | ||
91 | pcieow->pexowbar = (hose->mem_resources[i].start) >> 12 | ||
92 | & 0x000fffff; | ||
93 | /* Enable, Mem R/W */ | ||
94 | pcieow->pexowar = 0x80044000 | | ||
95 | (__ilog2(hose->mem_resources[i].end | ||
96 | - hose->mem_resources[i].start + 1) | ||
97 | - 1); | ||
98 | pcieow++; | ||
99 | } | ||
100 | |||
101 | /* Setup outbound IO window */ | ||
102 | if (hose->io_resource.flags & IORESOURCE_IO){ | ||
103 | DBG("PCIE IO resource start 0x%08x, size 0x%08x, phy base 0x%08x.\n", | ||
104 | hose->io_resource.start, | ||
105 | hose->io_resource.end - hose->io_resource.start + 1, | ||
106 | hose->io_base_phys); | ||
107 | pcieow->pexotar = (hose->io_resource.start) >> 12 & 0x000fffff; | ||
108 | pcieow->pexotear = 0; | ||
109 | pcieow->pexowbar = (hose->io_base_phys) >> 12 & 0x000fffff; | ||
110 | /* Enable, IO R/W */ | ||
111 | pcieow->pexowar = 0x80088000 | (__ilog2(hose->io_resource.end | ||
112 | - hose->io_resource.start + 1) - 1); | ||
113 | } | ||
114 | |||
115 | /* Setup 2G inbound Memory Window @ 0 */ | ||
116 | pcieiw->pexitar = 0x00000000; | ||
117 | pcieiw->pexiwbar = 0x00000000; | ||
118 | /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */ | ||
119 | pcieiw->pexiwar = 0xa0f5501e; | ||
120 | } | ||
121 | |||
122 | static void __init | ||
123 | mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) | ||
124 | { | ||
125 | volatile struct ccsr_pex *pcie; | ||
126 | u16 cmd; | ||
127 | unsigned int temps; | ||
128 | |||
129 | DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n", | ||
130 | pcie_offset, pcie_size); | ||
131 | |||
132 | pcie = ioremap(pcie_offset, pcie_size); | ||
133 | |||
134 | early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd); | ||
135 | cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | ||
136 | | PCI_COMMAND_IO; | ||
137 | early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); | ||
138 | |||
139 | early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); | ||
140 | |||
141 | /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */ | ||
142 | early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps); | ||
143 | temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); | ||
144 | early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); | ||
145 | } | ||
146 | |||
147 | int __init add_bridge(struct device_node *dev) | ||
148 | { | ||
149 | int len; | ||
150 | struct pci_controller *hose; | ||
151 | struct resource rsrc; | ||
152 | int *bus_range; | ||
153 | int has_address = 0; | ||
154 | int primary = 0; | ||
155 | |||
156 | DBG("Adding PCIE host bridge %s\n", dev->full_name); | ||
157 | |||
158 | /* Fetch host bridge registers address */ | ||
159 | has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); | ||
160 | |||
161 | /* Get bus range if any */ | ||
162 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
163 | if (bus_range == NULL || len < 2 * sizeof(int)) | ||
164 | printk(KERN_WARNING "Can't get bus-range for %s, assume" | ||
165 | " bus 0\n", dev->full_name); | ||
166 | |||
167 | hose = pcibios_alloc_controller(); | ||
168 | if (!hose) | ||
169 | return -ENOMEM; | ||
170 | hose->arch_data = dev; | ||
171 | hose->set_cfg_type = 1; | ||
172 | |||
173 | /* last_busno = 0xfe cause by MPC8641 PCIE bug */ | ||
174 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
175 | hose->last_busno = bus_range ? bus_range[1] : 0xfe; | ||
176 | |||
177 | setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4); | ||
178 | |||
179 | /* Setup the PCIE host controller. */ | ||
180 | mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); | ||
181 | |||
182 | if ((rsrc.start & 0xfffff) == 0x8000) | ||
183 | primary = 1; | ||
184 | |||
185 | printk(KERN_INFO "Found MPC86xx PCIE host bridge at 0x%08lx. " | ||
186 | "Firmware bus number: %d->%d\n", | ||
187 | rsrc.start, hose->first_busno, hose->last_busno); | ||
188 | |||
189 | DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", | ||
190 | hose, hose->cfg_addr, hose->cfg_data); | ||
191 | |||
192 | /* Interpret the "ranges" property */ | ||
193 | /* This also maps the I/O region and sets isa_io/mem_base */ | ||
194 | pci_process_bridge_OF_ranges(hose, dev, primary); | ||
195 | |||
196 | /* Setup PEX window registers */ | ||
197 | setup_pcie_atmu(hose, &rsrc); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static void __devinit quirk_ali1575(struct pci_dev *dev) | ||
203 | { | ||
204 | unsigned short temp; | ||
205 | |||
206 | /* | ||
207 | * ALI1575 interrupts route table setup: | ||
208 | * | ||
209 | * IRQ pin IRQ# | ||
210 | * PIRQA ---- 3 | ||
211 | * PIRQB ---- 4 | ||
212 | * PIRQC ---- 5 | ||
213 | * PIRQD ---- 6 | ||
214 | * PIRQE ---- 9 | ||
215 | * PIRQF ---- 10 | ||
216 | * PIRQG ---- 11 | ||
217 | * PIRQH ---- 12 | ||
218 | * | ||
219 | * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD | ||
220 | * PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA | ||
221 | */ | ||
222 | pci_write_config_dword(dev, 0x48, 0xb9317542); | ||
223 | |||
224 | /* USB 1.1 OHCI controller 1, interrupt: PIRQE */ | ||
225 | pci_write_config_byte(dev, 0x86, 0x0c); | ||
226 | |||
227 | /* USB 1.1 OHCI controller 2, interrupt: PIRQF */ | ||
228 | pci_write_config_byte(dev, 0x87, 0x0d); | ||
229 | |||
230 | /* USB 1.1 OHCI controller 3, interrupt: PIRQH */ | ||
231 | pci_write_config_byte(dev, 0x88, 0x0f); | ||
232 | |||
233 | /* USB 2.0 controller, interrupt: PIRQ7 */ | ||
234 | pci_write_config_byte(dev, 0x74, 0x06); | ||
235 | |||
236 | /* Audio controller, interrupt: PIRQE */ | ||
237 | pci_write_config_byte(dev, 0x8a, 0x0c); | ||
238 | |||
239 | /* Modem controller, interrupt: PIRQF */ | ||
240 | pci_write_config_byte(dev, 0x8b, 0x0d); | ||
241 | |||
242 | /* HD audio controller, interrupt: PIRQG */ | ||
243 | pci_write_config_byte(dev, 0x8c, 0x0e); | ||
244 | |||
245 | /* Serial ATA interrupt: PIRQD */ | ||
246 | pci_write_config_byte(dev, 0x8d, 0x0b); | ||
247 | |||
248 | /* SMB interrupt: PIRQH */ | ||
249 | pci_write_config_byte(dev, 0x8e, 0x0f); | ||
250 | |||
251 | /* PMU ACPI SCI interrupt: PIRQH */ | ||
252 | pci_write_config_byte(dev, 0x8f, 0x0f); | ||
253 | |||
254 | /* Primary PATA IDE IRQ: 14 | ||
255 | * Secondary PATA IDE IRQ: 15 | ||
256 | */ | ||
257 | pci_write_config_byte(dev, 0x44, 0x3d); | ||
258 | pci_write_config_byte(dev, 0x75, 0x0f); | ||
259 | |||
260 | /* Set IRQ14 and IRQ15 to legacy IRQs */ | ||
261 | pci_read_config_word(dev, 0x46, &temp); | ||
262 | temp |= 0xc000; | ||
263 | pci_write_config_word(dev, 0x46, temp); | ||
264 | |||
265 | /* Set i8259 interrupt trigger | ||
266 | * IRQ 3: Level | ||
267 | * IRQ 4: Level | ||
268 | * IRQ 5: Level | ||
269 | * IRQ 6: Level | ||
270 | * IRQ 7: Level | ||
271 | * IRQ 9: Level | ||
272 | * IRQ 10: Level | ||
273 | * IRQ 11: Level | ||
274 | * IRQ 12: Level | ||
275 | * IRQ 14: Edge | ||
276 | * IRQ 15: Edge | ||
277 | */ | ||
278 | outb(0xfa, 0x4d0); | ||
279 | outb(0x1e, 0x4d1); | ||
280 | } | ||
281 | |||
282 | static void __devinit quirk_uli5288(struct pci_dev *dev) | ||
283 | { | ||
284 | unsigned char c; | ||
285 | |||
286 | pci_read_config_byte(dev,0x83,&c); | ||
287 | c |= 0x80; | ||
288 | pci_write_config_byte(dev, 0x83, c); | ||
289 | |||
290 | pci_write_config_byte(dev, 0x09, 0x01); | ||
291 | pci_write_config_byte(dev, 0x0a, 0x06); | ||
292 | |||
293 | pci_read_config_byte(dev,0x83,&c); | ||
294 | c &= 0x7f; | ||
295 | pci_write_config_byte(dev, 0x83, c); | ||
296 | |||
297 | pci_read_config_byte(dev,0x84,&c); | ||
298 | c |= 0x01; | ||
299 | pci_write_config_byte(dev, 0x84, c); | ||
300 | } | ||
301 | |||
302 | static void __devinit quirk_uli5229(struct pci_dev *dev) | ||
303 | { | ||
304 | unsigned short temp; | ||
305 | pci_write_config_word(dev, 0x04, 0x0405); | ||
306 | pci_read_config_word(dev, 0x4a, &temp); | ||
307 | temp |= 0x1000; | ||
308 | pci_write_config_word(dev, 0x4a, temp); | ||
309 | } | ||
310 | |||
311 | static void __devinit early_uli5249(struct pci_dev *dev) | ||
312 | { | ||
313 | unsigned char temp; | ||
314 | pci_write_config_word(dev, 0x04, 0x0007); | ||
315 | pci_read_config_byte(dev, 0x7c, &temp); | ||
316 | pci_write_config_byte(dev, 0x7c, 0x80); | ||
317 | pci_write_config_byte(dev, 0x09, 0x01); | ||
318 | pci_write_config_byte(dev, 0x7c, temp); | ||
319 | dev->class |= 0x1; | ||
320 | } | ||
321 | |||
322 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_ali1575); | ||
323 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288); | ||
324 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); | ||
325 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249); | ||