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 
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 != 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 
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  */
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 };
222