Commit | Line | Data |
---|---|---|
591f0a42 AF |
1 | /* |
2 | * MPC85xx setup and early boot code plus other random bits. | |
3 | * | |
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | |
5 | * | |
ad68ee01 | 6 | * Copyright 2005, 2011-2012 Freescale Semiconductor Inc. |
591f0a42 AF |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2 of the License, or (at your | |
11 | * option) any later version. | |
12 | */ | |
13 | ||
591f0a42 AF |
14 | #include <linux/stddef.h> |
15 | #include <linux/kernel.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/errno.h> | |
18 | #include <linux/reboot.h> | |
19 | #include <linux/pci.h> | |
20 | #include <linux/kdev_t.h> | |
21 | #include <linux/major.h> | |
22 | #include <linux/console.h> | |
23 | #include <linux/delay.h> | |
24 | #include <linux/seq_file.h> | |
591f0a42 | 25 | #include <linux/initrd.h> |
3620fc1d | 26 | #include <linux/interrupt.h> |
591f0a42 | 27 | #include <linux/fsl_devices.h> |
a64887eb | 28 | #include <linux/of_platform.h> |
591f0a42 | 29 | |
591f0a42 AF |
30 | #include <asm/pgtable.h> |
31 | #include <asm/page.h> | |
60063497 | 32 | #include <linux/atomic.h> |
591f0a42 AF |
33 | #include <asm/time.h> |
34 | #include <asm/io.h> | |
35 | #include <asm/machdep.h> | |
36 | #include <asm/ipic.h> | |
591f0a42 | 37 | #include <asm/pci-bridge.h> |
591f0a42 AF |
38 | #include <asm/irq.h> |
39 | #include <mm/mmu_decl.h> | |
40 | #include <asm/prom.h> | |
41 | #include <asm/udbg.h> | |
42 | #include <asm/mpic.h> | |
43 | #include <asm/i8259.h> | |
44 | ||
45 | #include <sysdev/fsl_soc.h> | |
3f6c5dae | 46 | #include <sysdev/fsl_pci.h> |
591f0a42 | 47 | |
543a07b1 DES |
48 | #include "mpc85xx.h" |
49 | ||
992608ff | 50 | /* |
51 | * The CDS board contains an FPGA/CPLD called "Cadmus", which collects | |
52 | * various logic and performs system control functions. | |
53 | * Here is the FPGA/CPLD register map. | |
54 | */ | |
55 | struct cadmus_reg { | |
56 | u8 cm_ver; /* Board version */ | |
57 | u8 cm_csr; /* General control/status */ | |
58 | u8 cm_rst; /* Reset control */ | |
59 | u8 cm_hsclk; /* High speed clock */ | |
60 | u8 cm_hsxclk; /* High speed clock extended */ | |
61 | u8 cm_led; /* LED data */ | |
62 | u8 cm_pci; /* PCI control/status */ | |
63 | u8 cm_dma; /* DMA control */ | |
64 | u8 res[248]; /* Total 256 bytes */ | |
65 | }; | |
0bfd5df5 | 66 | |
992608ff | 67 | static struct cadmus_reg *cadmus; |
591f0a42 | 68 | |
591f0a42 | 69 | #ifdef CONFIG_PCI |
591f0a42 AF |
70 | |
71 | #define ARCADIA_HOST_BRIDGE_IDSEL 17 | |
72 | #define ARCADIA_2ND_BRIDGE_IDSEL 3 | |
73 | ||
7d52c7b0 KG |
74 | static int mpc85xx_exclude_device(struct pci_controller *hose, |
75 | u_char bus, u_char devfn) | |
591f0a42 | 76 | { |
591f0a42 AF |
77 | /* We explicitly do not go past the Tundra 320 Bridge */ |
78 | if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) | |
79 | return PCIBIOS_DEVICE_NOT_FOUND; | |
80 | if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) | |
81 | return PCIBIOS_DEVICE_NOT_FOUND; | |
82 | else | |
83 | return PCIBIOS_SUCCESSFUL; | |
84 | } | |
85 | ||
637e9e13 RV |
86 | static void mpc85xx_cds_restart(char *cmd) |
87 | { | |
88 | struct pci_dev *dev; | |
89 | u_char tmp; | |
90 | ||
91 | if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, | |
92 | NULL))) { | |
93 | ||
94 | /* Use the VIA Super Southbridge to force a PCI reset */ | |
95 | pci_read_config_byte(dev, 0x47, &tmp); | |
96 | pci_write_config_byte(dev, 0x47, tmp | 1); | |
97 | ||
98 | /* Flush the outbound PCI write queues */ | |
99 | pci_read_config_byte(dev, 0x47, &tmp); | |
100 | ||
101 | /* | |
102 | * At this point, the harware reset should have triggered. | |
103 | * However, if it doesn't work for some mysterious reason, | |
104 | * just fall through to the default reset below. | |
105 | */ | |
106 | ||
107 | pci_dev_put(dev); | |
108 | } | |
109 | ||
110 | /* | |
111 | * If we can't find the VIA chip (maybe the P2P bridge is disabled) | |
112 | * or the VIA chip reset didn't work, just use the default reset. | |
113 | */ | |
e1c1575f | 114 | fsl_rstcr_restart(NULL); |
637e9e13 RV |
115 | } |
116 | ||
749e8081 | 117 | static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev) |
591f0a42 | 118 | { |
749e8081 RZ |
119 | u_char c; |
120 | if (dev->vendor == PCI_VENDOR_ID_VIA) { | |
121 | switch (dev->device) { | |
122 | case PCI_DEVICE_ID_VIA_82C586_1: | |
123 | /* | |
124 | * U-Boot does not set the enable bits | |
125 | * for the IDE device. Force them on here. | |
126 | */ | |
127 | pci_read_config_byte(dev, 0x40, &c); | |
128 | c |= 0x03; /* IDE: Chip Enable Bits */ | |
129 | pci_write_config_byte(dev, 0x40, c); | |
130 | ||
131 | /* | |
132 | * Since only primary interface works, force the | |
133 | * IDE function to standard primary IDE interrupt | |
134 | * w/ 8259 offset | |
135 | */ | |
136 | dev->irq = 14; | |
137 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | |
138 | break; | |
591f0a42 | 139 | /* |
749e8081 | 140 | * Force legacy USB interrupt routing |
591f0a42 | 141 | */ |
749e8081 RZ |
142 | case PCI_DEVICE_ID_VIA_82C586_2: |
143 | /* There are two USB controllers. | |
144 | * Identify them by functon number | |
591f0a42 | 145 | */ |
8d7bc8f9 | 146 | if (PCI_FUNC(dev->devfn) == 3) |
749e8081 RZ |
147 | dev->irq = 11; |
148 | else | |
149 | dev->irq = 10; | |
150 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | |
151 | default: | |
152 | break; | |
153 | } | |
591f0a42 | 154 | } |
ddd64159 AF |
155 | } |
156 | ||
cad5cef6 | 157 | static void skip_fake_bridge(struct pci_dev *dev) |
4e798211 KG |
158 | { |
159 | /* Make it an error to skip the fake bridge | |
160 | * in pci_setup_device() in probe.c */ | |
161 | dev->hdr_type = 0x7f; | |
162 | } | |
163 | DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge); | |
164 | DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge); | |
165 | DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); | |
166 | ||
ad68ee01 | 167 | #define PCI_DEVICE_ID_IDT_TSI310 0x01a7 |
168 | ||
169 | /* | |
170 | * Fix Tsi310 PCI-X bridge resource. | |
171 | * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space. | |
172 | * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed. | |
173 | */ | |
174 | void mpc85xx_cds_fixup_bus(struct pci_bus *bus) | |
175 | { | |
176 | struct pci_dev *dev = bus->self; | |
177 | struct resource *res = bus->resource[0]; | |
178 | ||
179 | if (dev != NULL && | |
180 | dev->vendor == PCI_VENDOR_ID_IBM && | |
181 | dev->device == PCI_DEVICE_ID_IDT_TSI310) { | |
182 | if (res) { | |
183 | res->start = 0; | |
184 | res->end = 0x1fff; | |
185 | res->flags = IORESOURCE_IO; | |
186 | pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n"); | |
187 | pr_info("mpc85xx_cds: %pR\n", res); | |
188 | } | |
189 | } | |
190 | ||
191 | fsl_pcibios_fixup_bus(bus); | |
192 | } | |
193 | ||
ddd64159 | 194 | #ifdef CONFIG_PPC_I8259 |
3620fc1d RV |
195 | static void mpc85xx_8259_cascade_handler(unsigned int irq, |
196 | struct irq_desc *desc) | |
ddd64159 | 197 | { |
35a84c2f | 198 | unsigned int cascade_irq = i8259_irq(); |
ddd64159 AF |
199 | |
200 | if (cascade_irq != NO_IRQ) | |
3620fc1d | 201 | /* handle an interrupt from the 8259 */ |
49f19ce4 | 202 | generic_handle_irq(cascade_irq); |
ddd64159 | 203 | |
3620fc1d RV |
204 | /* check for any interrupts from the shared IRQ line */ |
205 | handle_fasteoi_irq(irq, desc); | |
591f0a42 | 206 | } |
3620fc1d RV |
207 | |
208 | static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id) | |
209 | { | |
210 | return IRQ_HANDLED; | |
211 | } | |
212 | ||
213 | static struct irqaction mpc85xxcds_8259_irqaction = { | |
214 | .handler = mpc85xx_8259_cascade_action, | |
c6c56bdd | 215 | .flags = IRQF_SHARED | IRQF_NO_THREAD, |
3620fc1d RV |
216 | .name = "8259 cascade", |
217 | }; | |
ddd64159 | 218 | #endif /* PPC_I8259 */ |
591f0a42 AF |
219 | #endif /* CONFIG_PCI */ |
220 | ||
27630bec | 221 | static void __init mpc85xx_cds_pic_init(void) |
591f0a42 | 222 | { |
ddd64159 | 223 | struct mpic *mpic; |
e55d7f73 | 224 | mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
b533f8ae | 225 | 0, 256, " OpenPIC "); |
ddd64159 | 226 | BUG_ON(mpic == NULL); |
ddd64159 | 227 | mpic_init(mpic); |
bca03c6b | 228 | } |
ddd64159 | 229 | |
3620fc1d | 230 | #if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI) |
bca03c6b RV |
231 | static int mpc85xx_cds_8259_attach(void) |
232 | { | |
233 | int ret; | |
234 | struct device_node *np = NULL; | |
235 | struct device_node *cascade_node = NULL; | |
236 | int cascade_irq; | |
237 | ||
ddd64159 AF |
238 | /* Initialize the i8259 controller */ |
239 | for_each_node_by_type(np, "interrupt-controller") | |
55b61fec | 240 | if (of_device_is_compatible(np, "chrp,iic")) { |
ddd64159 AF |
241 | cascade_node = np; |
242 | break; | |
243 | } | |
244 | ||
245 | if (cascade_node == NULL) { | |
246 | printk(KERN_DEBUG "Could not find i8259 PIC\n"); | |
bca03c6b | 247 | return -ENODEV; |
ddd64159 | 248 | } |
591f0a42 | 249 | |
ddd64159 AF |
250 | cascade_irq = irq_of_parse_and_map(cascade_node, 0); |
251 | if (cascade_irq == NO_IRQ) { | |
252 | printk(KERN_ERR "Failed to map cascade interrupt\n"); | |
bca03c6b | 253 | return -ENXIO; |
ddd64159 | 254 | } |
591f0a42 | 255 | |
ddd64159 AF |
256 | i8259_init(cascade_node, 0); |
257 | of_node_put(cascade_node); | |
258 | ||
3620fc1d RV |
259 | /* |
260 | * Hook the interrupt to make sure desc->action is never NULL. | |
261 | * This is required to ensure that the interrupt does not get | |
262 | * disabled when the last user of the shared IRQ line frees their | |
263 | * interrupt. | |
264 | */ | |
bca03c6b | 265 | if ((ret = setup_irq(cascade_irq, &mpc85xxcds_8259_irqaction))) { |
3620fc1d | 266 | printk(KERN_ERR "Failed to setup cascade interrupt\n"); |
bca03c6b RV |
267 | return ret; |
268 | } | |
269 | ||
270 | /* Success. Connect our low-level cascade handler. */ | |
ec775d0e | 271 | irq_set_handler(cascade_irq, mpc85xx_8259_cascade_handler); |
bca03c6b RV |
272 | |
273 | return 0; | |
591f0a42 | 274 | } |
277982e2 | 275 | machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); |
bca03c6b RV |
276 | |
277 | #endif /* CONFIG_PPC_I8259 */ | |
278 | ||
905e75c4 JH |
279 | static void mpc85xx_cds_pci_assign_primary(void) |
280 | { | |
281 | #ifdef CONFIG_PCI | |
282 | struct device_node *np; | |
283 | ||
284 | if (fsl_pci_primary) | |
285 | return; | |
286 | ||
287 | /* | |
288 | * MPC85xx_CDS has ISA bridge but unfortunately there is no | |
289 | * isa node in device tree. We now looking for i8259 node as | |
290 | * a workaround for such a broken device tree. This routine | |
291 | * is for complying to all device trees. | |
292 | */ | |
293 | np = of_find_node_by_name(NULL, "i8259"); | |
294 | while ((fsl_pci_primary = of_get_parent(np))) { | |
295 | of_node_put(np); | |
296 | np = fsl_pci_primary; | |
297 | ||
298 | if ((of_device_is_compatible(np, "fsl,mpc8540-pci") || | |
299 | of_device_is_compatible(np, "fsl,mpc8548-pcie")) && | |
300 | of_device_is_available(np)) | |
301 | return; | |
302 | } | |
303 | #endif | |
304 | } | |
305 | ||
591f0a42 AF |
306 | /* |
307 | * Setup the architecture | |
308 | */ | |
27630bec | 309 | static void __init mpc85xx_cds_setup_arch(void) |
591f0a42 | 310 | { |
591f0a42 | 311 | struct device_node *np; |
992608ff | 312 | int cds_pci_slot; |
591f0a42 AF |
313 | |
314 | if (ppc_md.progress) | |
315 | ppc_md.progress("mpc85xx_cds_setup_arch()", 0); | |
316 | ||
992608ff | 317 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga"); |
318 | if (!np) { | |
319 | pr_err("Could not find FPGA node.\n"); | |
320 | return; | |
321 | } | |
322 | ||
323 | cadmus = of_iomap(np, 0); | |
324 | of_node_put(np); | |
325 | if (!cadmus) { | |
326 | pr_err("Fail to map FPGA area.\n"); | |
327 | return; | |
328 | } | |
591f0a42 AF |
329 | |
330 | if (ppc_md.progress) { | |
331 | char buf[40]; | |
992608ff | 332 | cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1; |
591f0a42 | 333 | snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", |
992608ff | 334 | in_8(&cadmus->cm_ver), cds_pci_slot); |
591f0a42 AF |
335 | ppc_md.progress(buf, 0); |
336 | } | |
337 | ||
338 | #ifdef CONFIG_PCI | |
749e8081 | 339 | ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup; |
591f0a42 AF |
340 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; |
341 | #endif | |
905e75c4 JH |
342 | |
343 | mpc85xx_cds_pci_assign_primary(); | |
344 | fsl_pci_assign_primary(); | |
591f0a42 AF |
345 | } |
346 | ||
27630bec | 347 | static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) |
591f0a42 AF |
348 | { |
349 | uint pvid, svid, phid1; | |
591f0a42 AF |
350 | |
351 | pvid = mfspr(SPRN_PVR); | |
352 | svid = mfspr(SPRN_SVR); | |
353 | ||
354 | seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); | |
992608ff | 355 | seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", |
356 | in_8(&cadmus->cm_ver)); | |
591f0a42 AF |
357 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); |
358 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | |
359 | ||
360 | /* Display cpu Pll setting */ | |
361 | phid1 = mfspr(SPRN_HID1); | |
362 | seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); | |
591f0a42 AF |
363 | } |
364 | ||
365 | ||
366 | /* | |
367 | * Called very early, device-tree isn't unflattened | |
368 | */ | |
369 | static int __init mpc85xx_cds_probe(void) | |
370 | { | |
6936c625 KG |
371 | unsigned long root = of_get_flat_dt_root(); |
372 | ||
373 | return of_flat_dt_is_compatible(root, "MPC85xxCDS"); | |
591f0a42 AF |
374 | } |
375 | ||
905e75c4 | 376 | machine_arch_initcall(mpc85xx_cds, mpc85xx_common_publish_devices); |
a64887eb | 377 | |
591f0a42 AF |
378 | define_machine(mpc85xx_cds) { |
379 | .name = "MPC85xx CDS", | |
380 | .probe = mpc85xx_cds_probe, | |
381 | .setup_arch = mpc85xx_cds_setup_arch, | |
382 | .init_IRQ = mpc85xx_cds_pic_init, | |
383 | .show_cpuinfo = mpc85xx_cds_show_cpuinfo, | |
384 | .get_irq = mpic_get_irq, | |
637e9e13 RV |
385 | #ifdef CONFIG_PCI |
386 | .restart = mpc85xx_cds_restart, | |
ad68ee01 | 387 | .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, |
637e9e13 | 388 | #else |
e1c1575f | 389 | .restart = fsl_rstcr_restart, |
637e9e13 | 390 | #endif |
591f0a42 AF |
391 | .calibrate_decr = generic_calibrate_decr, |
392 | .progress = udbg_progress, | |
393 | }; |