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