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_irq.h>
16#include <linux/of_platform.h>
17
18#include <asm/i8259.h>
19#include <asm/pci-bridge.h>
20#include <asm/mpic.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
37static phys_addr_t pci_membase;
38static u_char *restart;
39
40static 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
51static 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
106static 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
147static const struct of_device_id mvme5100_of_bus_ids[] __initconst = {
148	{ .compatible = "hawk-bridge", },
149	{},
150};
151
152/*
153 * Setup the architecture
154 */
155static void __init mvme5100_setup_arch(void)
156{
157	if (ppc_md.progress)
158		ppc_md.progress("mvme5100_setup_arch()", 0);
159
160	restart = ioremap(BOARD_MODRST_REG, 4);
161}
162
163static void __init mvme5100_setup_pci(void)
164{
165	struct device_node *np;
166
167	for_each_compatible_node(np, "pci", "hawk-pci")
168		mvme5100_add_bridge(np);
169}
170
171static void mvme5100_show_cpuinfo(struct seq_file *m)
172{
173	seq_puts(m, "Vendor\t\t: Motorola/Emerson\n");
174	seq_puts(m, "Machine\t\t: MVME5100\n");
175}
176
177static void __noreturn mvme5100_restart(char *cmd)
178{
179
180	local_irq_disable();
181	mtmsr(mfmsr() | MSR_IP);
182
183	out_8((u_char *) restart, 0x01);
184
185	while (1)
186		;
187}
188
189static int __init probe_of_platform_devices(void)
190{
191
192	of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL);
193	return 0;
194}
195
196machine_device_initcall(mvme5100, probe_of_platform_devices);
197
198define_machine(mvme5100) {
199	.name			= "MVME5100",
200	.compatible		= "MVME5100",
201	.setup_arch		= mvme5100_setup_arch,
202	.discover_phbs		= mvme5100_setup_pci,
203	.init_IRQ		= mvme5100_pic_init,
204	.show_cpuinfo		= mvme5100_show_cpuinfo,
205	.get_irq		= mpic_get_irq,
206	.restart		= mvme5100_restart,
207	.progress		= udbg_progress,
208};
209