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