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