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
mvme5100_8259_cascade(struct irq_desc * desc)45 static void mvme5100_8259_cascade(struct irq_desc *desc)
46 {
47 struct irq_chip *chip = irq_desc_get_chip(desc);
48 unsigned int cascade_irq = i8259_irq();
49
50 if (cascade_irq)
51 generic_handle_irq(cascade_irq);
52
53 chip->irq_eoi(&desc->irq_data);
54 }
55
mvme5100_pic_init(void)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) {
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
mvme5100_add_bridge(struct device_node * dev)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 %pOF\n", dev);
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
152 static const struct of_device_id mvme5100_of_bus_ids[] __initconst = {
153 { .compatible = "hawk-bridge", },
154 {},
155 };
156
157 /*
158 * Setup the architecture
159 */
mvme5100_setup_arch(void)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
mvme5100_show_cpuinfo(struct seq_file * m)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
mvme5100_restart(char * cmd)180 static void __noreturn 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 */
mvme5100_probe(void)195 static int __init mvme5100_probe(void)
196 {
197 return of_machine_is_compatible("MVME5100");
198 }
199
probe_of_platform_devices(void)200 static int __init probe_of_platform_devices(void)
201 {
202
203 of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL);
204 return 0;
205 }
206
207 machine_device_initcall(mvme5100, probe_of_platform_devices);
208
define_machine(mvme5100)209 define_machine(mvme5100) {
210 .name = "MVME5100",
211 .probe = mvme5100_probe,
212 .setup_arch = mvme5100_setup_arch,
213 .init_IRQ = mvme5100_pic_init,
214 .show_cpuinfo = mvme5100_show_cpuinfo,
215 .get_irq = mpic_get_irq,
216 .restart = mvme5100_restart,
217 .calibrate_decr = generic_calibrate_decr,
218 .progress = udbg_progress,
219 };
220