]>
Commit | Line | Data |
---|---|---|
be201981 SC |
1 | /* |
2 | * Board setup routines for the Motorola/Emerson MVME5100. | |
3 | * | |
4 | * Copyright 2013 CSC Australia Pty. Ltd. | |
5 | * | |
6 | * Based on earlier code by: | |
7 | * | |
8 | * Matt Porter, MontaVista Software Inc. | |
9 | * Copyright 2001 MontaVista Software Inc. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2 of the License, or (at your | |
14 | * option) any later version. | |
15 | * | |
16 | * Author: Stephen Chivers <schivers@csc.com> | |
17 | * | |
18 | */ | |
19 | ||
20 | #include <linux/of_platform.h> | |
21 | ||
22 | #include <asm/i8259.h> | |
23 | #include <asm/pci-bridge.h> | |
24 | #include <asm/mpic.h> | |
25 | #include <asm/prom.h> | |
26 | #include <mm/mmu_decl.h> | |
27 | #include <asm/udbg.h> | |
28 | ||
29 | #define HAWK_MPIC_SIZE 0x00040000U | |
30 | #define MVME5100_PCI_MEM_OFFSET 0x00000000 | |
31 | ||
32 | /* Board register addresses. */ | |
33 | #define BOARD_STATUS_REG 0xfef88080 | |
34 | #define BOARD_MODFAIL_REG 0xfef88090 | |
35 | #define BOARD_MODRST_REG 0xfef880a0 | |
36 | #define BOARD_TBEN_REG 0xfef880c0 | |
37 | #define BOARD_SW_READ_REG 0xfef880e0 | |
38 | #define BOARD_GEO_ADDR_REG 0xfef880e8 | |
39 | #define BOARD_EXT_FEATURE1_REG 0xfef880f0 | |
40 | #define BOARD_EXT_FEATURE2_REG 0xfef88100 | |
41 | ||
42 | static phys_addr_t pci_membase; | |
43 | static u_char *restart; | |
44 | ||
bd0b9ac4 | 45 | static void mvme5100_8259_cascade(struct irq_desc *desc) |
be201981 SC |
46 | { |
47 | struct irq_chip *chip = irq_desc_get_chip(desc); | |
48 | unsigned int cascade_irq = i8259_irq(); | |
49 | ||
50 | if (cascade_irq != NO_IRQ) | |
51 | generic_handle_irq(cascade_irq); | |
52 | ||
53 | chip->irq_eoi(&desc->irq_data); | |
54 | } | |
55 | ||
56 | static void __init mvme5100_pic_init(void) | |
57 | { | |
58 | struct mpic *mpic; | |
59 | struct device_node *np; | |
60 | struct device_node *cp = NULL; | |
61 | unsigned int cirq; | |
62 | unsigned long intack = 0; | |
63 | const u32 *prop = NULL; | |
64 | ||
65 | np = of_find_node_by_type(NULL, "open-pic"); | |
66 | if (!np) { | |
67 | pr_err("Could not find open-pic node\n"); | |
68 | return; | |
69 | } | |
70 | ||
71 | mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC "); | |
72 | ||
73 | BUG_ON(mpic == NULL); | |
74 | of_node_put(np); | |
75 | ||
76 | mpic_assign_isu(mpic, 0, pci_membase + 0x10000); | |
77 | ||
78 | mpic_init(mpic); | |
79 | ||
80 | cp = of_find_compatible_node(NULL, NULL, "chrp,iic"); | |
81 | if (cp == NULL) { | |
82 | pr_warn("mvme5100_pic_init: couldn't find i8259\n"); | |
83 | return; | |
84 | } | |
85 | ||
86 | cirq = irq_of_parse_and_map(cp, 0); | |
87 | if (cirq == NO_IRQ) { | |
88 | pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); | |
89 | return; | |
90 | } | |
91 | ||
92 | np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"); | |
93 | if (np) { | |
94 | prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); | |
95 | ||
96 | if (prop) | |
97 | intack = prop[0]; | |
98 | ||
99 | of_node_put(np); | |
100 | } | |
101 | ||
102 | if (intack) | |
103 | pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n", | |
104 | intack); | |
105 | ||
106 | i8259_init(cp, intack); | |
107 | of_node_put(cp); | |
108 | irq_set_chained_handler(cirq, mvme5100_8259_cascade); | |
109 | } | |
110 | ||
111 | static int __init mvme5100_add_bridge(struct device_node *dev) | |
112 | { | |
113 | const int *bus_range; | |
114 | int len; | |
115 | struct pci_controller *hose; | |
116 | unsigned short devid; | |
117 | ||
118 | pr_info("Adding PCI host bridge %s\n", dev->full_name); | |
119 | ||
120 | bus_range = of_get_property(dev, "bus-range", &len); | |
121 | ||
122 | hose = pcibios_alloc_controller(dev); | |
123 | if (hose == NULL) | |
124 | return -ENOMEM; | |
125 | ||
126 | hose->first_busno = bus_range ? bus_range[0] : 0; | |
127 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | |
128 | ||
129 | setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0); | |
130 | ||
131 | pci_process_bridge_OF_ranges(hose, dev, 1); | |
132 | ||
133 | early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid); | |
134 | ||
135 | if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) { | |
136 | pr_err("HAWK PHB not present?\n"); | |
137 | return 0; | |
138 | } | |
139 | ||
140 | early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); | |
141 | ||
142 | if (pci_membase == 0) { | |
143 | pr_err("HAWK PHB mibar not correctly set?\n"); | |
144 | return 0; | |
145 | } | |
146 | ||
147 | pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase); | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
ce6d73c9 | 152 | static const struct of_device_id mvme5100_of_bus_ids[] __initconst = { |
be201981 SC |
153 | { .compatible = "hawk-bridge", }, |
154 | {}, | |
155 | }; | |
156 | ||
157 | /* | |
158 | * Setup the architecture | |
159 | */ | |
160 | static void __init mvme5100_setup_arch(void) | |
161 | { | |
162 | struct device_node *np; | |
163 | ||
164 | if (ppc_md.progress) | |
165 | ppc_md.progress("mvme5100_setup_arch()", 0); | |
166 | ||
167 | for_each_compatible_node(np, "pci", "hawk-pci") | |
168 | mvme5100_add_bridge(np); | |
169 | ||
170 | restart = ioremap(BOARD_MODRST_REG, 4); | |
171 | } | |
172 | ||
173 | ||
174 | static void mvme5100_show_cpuinfo(struct seq_file *m) | |
175 | { | |
176 | seq_puts(m, "Vendor\t\t: Motorola/Emerson\n"); | |
177 | seq_puts(m, "Machine\t\t: MVME5100\n"); | |
178 | } | |
179 | ||
180 | static void mvme5100_restart(char *cmd) | |
181 | { | |
182 | ||
183 | local_irq_disable(); | |
184 | mtmsr(mfmsr() | MSR_IP); | |
185 | ||
186 | out_8((u_char *) restart, 0x01); | |
187 | ||
188 | while (1) | |
189 | ; | |
190 | } | |
191 | ||
192 | /* | |
193 | * Called very early, device-tree isn't unflattened | |
194 | */ | |
195 | static int __init mvme5100_probe(void) | |
196 | { | |
197 | unsigned long root = of_get_flat_dt_root(); | |
198 | ||
199 | return of_flat_dt_is_compatible(root, "MVME5100"); | |
200 | } | |
201 | ||
202 | static int __init probe_of_platform_devices(void) | |
203 | { | |
204 | ||
205 | of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL); | |
206 | return 0; | |
207 | } | |
208 | ||
209 | machine_device_initcall(mvme5100, probe_of_platform_devices); | |
210 | ||
211 | define_machine(mvme5100) { | |
212 | .name = "MVME5100", | |
213 | .probe = mvme5100_probe, | |
214 | .setup_arch = mvme5100_setup_arch, | |
215 | .init_IRQ = mvme5100_pic_init, | |
216 | .show_cpuinfo = mvme5100_show_cpuinfo, | |
217 | .get_irq = mpic_get_irq, | |
218 | .restart = mvme5100_restart, | |
219 | .calibrate_decr = generic_calibrate_decr, | |
220 | .progress = udbg_progress, | |
221 | }; |