xref: /openbmc/linux/arch/sparc/kernel/prom_64.c (revision efeac2f8)
1a88b5ba8SSam Ravnborg /*
2a88b5ba8SSam Ravnborg  * Procedures for creating, accessing and interpreting the device tree.
3a88b5ba8SSam Ravnborg  *
4a88b5ba8SSam Ravnborg  * Paul Mackerras	August 1996.
5a88b5ba8SSam Ravnborg  * Copyright (C) 1996-2005 Paul Mackerras.
6a88b5ba8SSam Ravnborg  *
7a88b5ba8SSam Ravnborg  *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
8a88b5ba8SSam Ravnborg  *    {engebret|bergner}@us.ibm.com
9a88b5ba8SSam Ravnborg  *
10a88b5ba8SSam Ravnborg  *  Adapted for sparc64 by David S. Miller davem@davemloft.net
11a88b5ba8SSam Ravnborg  *
12a88b5ba8SSam Ravnborg  *      This program is free software; you can redistribute it and/or
13a88b5ba8SSam Ravnborg  *      modify it under the terms of the GNU General Public License
14a88b5ba8SSam Ravnborg  *      as published by the Free Software Foundation; either version
15a88b5ba8SSam Ravnborg  *      2 of the License, or (at your option) any later version.
16a88b5ba8SSam Ravnborg  */
17a88b5ba8SSam Ravnborg 
18a88b5ba8SSam Ravnborg #include <linux/kernel.h>
19a88b5ba8SSam Ravnborg #include <linux/types.h>
20a88b5ba8SSam Ravnborg #include <linux/string.h>
21a88b5ba8SSam Ravnborg #include <linux/mm.h>
22a88b5ba8SSam Ravnborg #include <linux/module.h>
23a88b5ba8SSam Ravnborg #include <linux/lmb.h>
24a88b5ba8SSam Ravnborg #include <linux/of_device.h>
25a88b5ba8SSam Ravnborg 
26a88b5ba8SSam Ravnborg #include <asm/prom.h>
27a88b5ba8SSam Ravnborg #include <asm/oplib.h>
28a88b5ba8SSam Ravnborg #include <asm/irq.h>
29a88b5ba8SSam Ravnborg #include <asm/asi.h>
30a88b5ba8SSam Ravnborg #include <asm/upa.h>
31a88b5ba8SSam Ravnborg #include <asm/smp.h>
32a88b5ba8SSam Ravnborg 
33657f201dSDavid S. Miller #include "prom.h"
34a88b5ba8SSam Ravnborg 
35a88b5ba8SSam Ravnborg static unsigned int prom_early_allocated __initdata;
36a88b5ba8SSam Ravnborg 
37efeac2f8SDavid S. Miller void * __init prom_early_alloc(unsigned long size)
38a88b5ba8SSam Ravnborg {
39a88b5ba8SSam Ravnborg 	unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES);
40a88b5ba8SSam Ravnborg 	void *ret;
41a88b5ba8SSam Ravnborg 
42a88b5ba8SSam Ravnborg 	if (!paddr) {
43a88b5ba8SSam Ravnborg 		prom_printf("prom_early_alloc(%lu) failed\n");
44a88b5ba8SSam Ravnborg 		prom_halt();
45a88b5ba8SSam Ravnborg 	}
46a88b5ba8SSam Ravnborg 
47a88b5ba8SSam Ravnborg 	ret = __va(paddr);
48a88b5ba8SSam Ravnborg 	memset(ret, 0, size);
49a88b5ba8SSam Ravnborg 	prom_early_allocated += size;
50a88b5ba8SSam Ravnborg 
51a88b5ba8SSam Ravnborg 	return ret;
52a88b5ba8SSam Ravnborg }
53a88b5ba8SSam Ravnborg 
54a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI
55a88b5ba8SSam Ravnborg /* PSYCHO interrupt mapping support. */
56a88b5ba8SSam Ravnborg #define PSYCHO_IMAP_A_SLOT0	0x0c00UL
57a88b5ba8SSam Ravnborg #define PSYCHO_IMAP_B_SLOT0	0x0c20UL
58a88b5ba8SSam Ravnborg static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
59a88b5ba8SSam Ravnborg {
60a88b5ba8SSam Ravnborg 	unsigned int bus =  (ino & 0x10) >> 4;
61a88b5ba8SSam Ravnborg 	unsigned int slot = (ino & 0x0c) >> 2;
62a88b5ba8SSam Ravnborg 
63a88b5ba8SSam Ravnborg 	if (bus == 0)
64a88b5ba8SSam Ravnborg 		return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
65a88b5ba8SSam Ravnborg 	else
66a88b5ba8SSam Ravnborg 		return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
67a88b5ba8SSam Ravnborg }
68a88b5ba8SSam Ravnborg 
69a88b5ba8SSam Ravnborg #define PSYCHO_OBIO_IMAP_BASE	0x1000UL
70a88b5ba8SSam Ravnborg 
71a88b5ba8SSam Ravnborg #define PSYCHO_ONBOARD_IRQ_BASE		0x20
72a88b5ba8SSam Ravnborg #define psycho_onboard_imap_offset(__ino) \
73a88b5ba8SSam Ravnborg 	(PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
74a88b5ba8SSam Ravnborg 
75a88b5ba8SSam Ravnborg #define PSYCHO_ICLR_A_SLOT0	0x1400UL
76a88b5ba8SSam Ravnborg #define PSYCHO_ICLR_SCSI	0x1800UL
77a88b5ba8SSam Ravnborg 
78a88b5ba8SSam Ravnborg #define psycho_iclr_offset(ino)					      \
79a88b5ba8SSam Ravnborg 	((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
80a88b5ba8SSam Ravnborg 			(PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
81a88b5ba8SSam Ravnborg 
82a88b5ba8SSam Ravnborg static unsigned int psycho_irq_build(struct device_node *dp,
83a88b5ba8SSam Ravnborg 				     unsigned int ino,
84a88b5ba8SSam Ravnborg 				     void *_data)
85a88b5ba8SSam Ravnborg {
86a88b5ba8SSam Ravnborg 	unsigned long controller_regs = (unsigned long) _data;
87a88b5ba8SSam Ravnborg 	unsigned long imap, iclr;
88a88b5ba8SSam Ravnborg 	unsigned long imap_off, iclr_off;
89a88b5ba8SSam Ravnborg 	int inofixup = 0;
90a88b5ba8SSam Ravnborg 
91a88b5ba8SSam Ravnborg 	ino &= 0x3f;
92a88b5ba8SSam Ravnborg 	if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
93a88b5ba8SSam Ravnborg 		/* PCI slot */
94a88b5ba8SSam Ravnborg 		imap_off = psycho_pcislot_imap_offset(ino);
95a88b5ba8SSam Ravnborg 	} else {
96a88b5ba8SSam Ravnborg 		/* Onboard device */
97a88b5ba8SSam Ravnborg 		imap_off = psycho_onboard_imap_offset(ino);
98a88b5ba8SSam Ravnborg 	}
99a88b5ba8SSam Ravnborg 
100a88b5ba8SSam Ravnborg 	/* Now build the IRQ bucket. */
101a88b5ba8SSam Ravnborg 	imap = controller_regs + imap_off;
102a88b5ba8SSam Ravnborg 
103a88b5ba8SSam Ravnborg 	iclr_off = psycho_iclr_offset(ino);
104a88b5ba8SSam Ravnborg 	iclr = controller_regs + iclr_off;
105a88b5ba8SSam Ravnborg 
106a88b5ba8SSam Ravnborg 	if ((ino & 0x20) == 0)
107a88b5ba8SSam Ravnborg 		inofixup = ino & 0x03;
108a88b5ba8SSam Ravnborg 
109a88b5ba8SSam Ravnborg 	return build_irq(inofixup, iclr, imap);
110a88b5ba8SSam Ravnborg }
111a88b5ba8SSam Ravnborg 
112a88b5ba8SSam Ravnborg static void __init psycho_irq_trans_init(struct device_node *dp)
113a88b5ba8SSam Ravnborg {
114a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
115a88b5ba8SSam Ravnborg 
116a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
117a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = psycho_irq_build;
118a88b5ba8SSam Ravnborg 
119a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
120a88b5ba8SSam Ravnborg 	dp->irq_trans->data = (void *) regs[2].phys_addr;
121a88b5ba8SSam Ravnborg }
122a88b5ba8SSam Ravnborg 
123a88b5ba8SSam Ravnborg #define sabre_read(__reg) \
124a88b5ba8SSam Ravnborg ({	u64 __ret; \
125a88b5ba8SSam Ravnborg 	__asm__ __volatile__("ldxa [%1] %2, %0" \
126a88b5ba8SSam Ravnborg 			     : "=r" (__ret) \
127a88b5ba8SSam Ravnborg 			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
128a88b5ba8SSam Ravnborg 			     : "memory"); \
129a88b5ba8SSam Ravnborg 	__ret; \
130a88b5ba8SSam Ravnborg })
131a88b5ba8SSam Ravnborg 
132a88b5ba8SSam Ravnborg struct sabre_irq_data {
133a88b5ba8SSam Ravnborg 	unsigned long controller_regs;
134a88b5ba8SSam Ravnborg 	unsigned int pci_first_busno;
135a88b5ba8SSam Ravnborg };
136a88b5ba8SSam Ravnborg #define SABRE_CONFIGSPACE	0x001000000UL
137a88b5ba8SSam Ravnborg #define SABRE_WRSYNC		0x1c20UL
138a88b5ba8SSam Ravnborg 
139a88b5ba8SSam Ravnborg #define SABRE_CONFIG_BASE(CONFIG_SPACE)	\
140a88b5ba8SSam Ravnborg 	(CONFIG_SPACE | (1UL << 24))
141a88b5ba8SSam Ravnborg #define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
142a88b5ba8SSam Ravnborg 	(((unsigned long)(BUS)   << 16) |	\
143a88b5ba8SSam Ravnborg 	 ((unsigned long)(DEVFN) << 8)  |	\
144a88b5ba8SSam Ravnborg 	 ((unsigned long)(REG)))
145a88b5ba8SSam Ravnborg 
146a88b5ba8SSam Ravnborg /* When a device lives behind a bridge deeper in the PCI bus topology
147a88b5ba8SSam Ravnborg  * than APB, a special sequence must run to make sure all pending DMA
148a88b5ba8SSam Ravnborg  * transfers at the time of IRQ delivery are visible in the coherency
149a88b5ba8SSam Ravnborg  * domain by the cpu.  This sequence is to perform a read on the far
150a88b5ba8SSam Ravnborg  * side of the non-APB bridge, then perform a read of Sabre's DMA
151a88b5ba8SSam Ravnborg  * write-sync register.
152a88b5ba8SSam Ravnborg  */
153a88b5ba8SSam Ravnborg static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
154a88b5ba8SSam Ravnborg {
155a88b5ba8SSam Ravnborg 	unsigned int phys_hi = (unsigned int) (unsigned long) _arg1;
156a88b5ba8SSam Ravnborg 	struct sabre_irq_data *irq_data = _arg2;
157a88b5ba8SSam Ravnborg 	unsigned long controller_regs = irq_data->controller_regs;
158a88b5ba8SSam Ravnborg 	unsigned long sync_reg = controller_regs + SABRE_WRSYNC;
159a88b5ba8SSam Ravnborg 	unsigned long config_space = controller_regs + SABRE_CONFIGSPACE;
160a88b5ba8SSam Ravnborg 	unsigned int bus, devfn;
161a88b5ba8SSam Ravnborg 	u16 _unused;
162a88b5ba8SSam Ravnborg 
163a88b5ba8SSam Ravnborg 	config_space = SABRE_CONFIG_BASE(config_space);
164a88b5ba8SSam Ravnborg 
165a88b5ba8SSam Ravnborg 	bus = (phys_hi >> 16) & 0xff;
166a88b5ba8SSam Ravnborg 	devfn = (phys_hi >> 8) & 0xff;
167a88b5ba8SSam Ravnborg 
168a88b5ba8SSam Ravnborg 	config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00);
169a88b5ba8SSam Ravnborg 
170a88b5ba8SSam Ravnborg 	__asm__ __volatile__("membar #Sync\n\t"
171a88b5ba8SSam Ravnborg 			     "lduha [%1] %2, %0\n\t"
172a88b5ba8SSam Ravnborg 			     "membar #Sync"
173a88b5ba8SSam Ravnborg 			     : "=r" (_unused)
174a88b5ba8SSam Ravnborg 			     : "r" ((u16 *) config_space),
175a88b5ba8SSam Ravnborg 			       "i" (ASI_PHYS_BYPASS_EC_E_L)
176a88b5ba8SSam Ravnborg 			     : "memory");
177a88b5ba8SSam Ravnborg 
178a88b5ba8SSam Ravnborg 	sabre_read(sync_reg);
179a88b5ba8SSam Ravnborg }
180a88b5ba8SSam Ravnborg 
181a88b5ba8SSam Ravnborg #define SABRE_IMAP_A_SLOT0	0x0c00UL
182a88b5ba8SSam Ravnborg #define SABRE_IMAP_B_SLOT0	0x0c20UL
183a88b5ba8SSam Ravnborg #define SABRE_ICLR_A_SLOT0	0x1400UL
184a88b5ba8SSam Ravnborg #define SABRE_ICLR_B_SLOT0	0x1480UL
185a88b5ba8SSam Ravnborg #define SABRE_ICLR_SCSI		0x1800UL
186a88b5ba8SSam Ravnborg #define SABRE_ICLR_ETH		0x1808UL
187a88b5ba8SSam Ravnborg #define SABRE_ICLR_BPP		0x1810UL
188a88b5ba8SSam Ravnborg #define SABRE_ICLR_AU_REC	0x1818UL
189a88b5ba8SSam Ravnborg #define SABRE_ICLR_AU_PLAY	0x1820UL
190a88b5ba8SSam Ravnborg #define SABRE_ICLR_PFAIL	0x1828UL
191a88b5ba8SSam Ravnborg #define SABRE_ICLR_KMS		0x1830UL
192a88b5ba8SSam Ravnborg #define SABRE_ICLR_FLPY		0x1838UL
193a88b5ba8SSam Ravnborg #define SABRE_ICLR_SHW		0x1840UL
194a88b5ba8SSam Ravnborg #define SABRE_ICLR_KBD		0x1848UL
195a88b5ba8SSam Ravnborg #define SABRE_ICLR_MS		0x1850UL
196a88b5ba8SSam Ravnborg #define SABRE_ICLR_SER		0x1858UL
197a88b5ba8SSam Ravnborg #define SABRE_ICLR_UE		0x1870UL
198a88b5ba8SSam Ravnborg #define SABRE_ICLR_CE		0x1878UL
199a88b5ba8SSam Ravnborg #define SABRE_ICLR_PCIERR	0x1880UL
200a88b5ba8SSam Ravnborg 
201a88b5ba8SSam Ravnborg static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
202a88b5ba8SSam Ravnborg {
203a88b5ba8SSam Ravnborg 	unsigned int bus =  (ino & 0x10) >> 4;
204a88b5ba8SSam Ravnborg 	unsigned int slot = (ino & 0x0c) >> 2;
205a88b5ba8SSam Ravnborg 
206a88b5ba8SSam Ravnborg 	if (bus == 0)
207a88b5ba8SSam Ravnborg 		return SABRE_IMAP_A_SLOT0 + (slot * 8);
208a88b5ba8SSam Ravnborg 	else
209a88b5ba8SSam Ravnborg 		return SABRE_IMAP_B_SLOT0 + (slot * 8);
210a88b5ba8SSam Ravnborg }
211a88b5ba8SSam Ravnborg 
212a88b5ba8SSam Ravnborg #define SABRE_OBIO_IMAP_BASE	0x1000UL
213a88b5ba8SSam Ravnborg #define SABRE_ONBOARD_IRQ_BASE	0x20
214a88b5ba8SSam Ravnborg #define sabre_onboard_imap_offset(__ino) \
215a88b5ba8SSam Ravnborg 	(SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
216a88b5ba8SSam Ravnborg 
217a88b5ba8SSam Ravnborg #define sabre_iclr_offset(ino)					      \
218a88b5ba8SSam Ravnborg 	((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
219a88b5ba8SSam Ravnborg 			(SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
220a88b5ba8SSam Ravnborg 
221a88b5ba8SSam Ravnborg static int sabre_device_needs_wsync(struct device_node *dp)
222a88b5ba8SSam Ravnborg {
223a88b5ba8SSam Ravnborg 	struct device_node *parent = dp->parent;
224a88b5ba8SSam Ravnborg 	const char *parent_model, *parent_compat;
225a88b5ba8SSam Ravnborg 
226a88b5ba8SSam Ravnborg 	/* This traversal up towards the root is meant to
227a88b5ba8SSam Ravnborg 	 * handle two cases:
228a88b5ba8SSam Ravnborg 	 *
229a88b5ba8SSam Ravnborg 	 * 1) non-PCI bus sitting under PCI, such as 'ebus'
230a88b5ba8SSam Ravnborg 	 * 2) the PCI controller interrupts themselves, which
231a88b5ba8SSam Ravnborg 	 *    will use the sabre_irq_build but do not need
232a88b5ba8SSam Ravnborg 	 *    the DMA synchronization handling
233a88b5ba8SSam Ravnborg 	 */
234a88b5ba8SSam Ravnborg 	while (parent) {
235a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "pci"))
236a88b5ba8SSam Ravnborg 			break;
237a88b5ba8SSam Ravnborg 		parent = parent->parent;
238a88b5ba8SSam Ravnborg 	}
239a88b5ba8SSam Ravnborg 
240a88b5ba8SSam Ravnborg 	if (!parent)
241a88b5ba8SSam Ravnborg 		return 0;
242a88b5ba8SSam Ravnborg 
243a88b5ba8SSam Ravnborg 	parent_model = of_get_property(parent,
244a88b5ba8SSam Ravnborg 				       "model", NULL);
245a88b5ba8SSam Ravnborg 	if (parent_model &&
246a88b5ba8SSam Ravnborg 	    (!strcmp(parent_model, "SUNW,sabre") ||
247a88b5ba8SSam Ravnborg 	     !strcmp(parent_model, "SUNW,simba")))
248a88b5ba8SSam Ravnborg 		return 0;
249a88b5ba8SSam Ravnborg 
250a88b5ba8SSam Ravnborg 	parent_compat = of_get_property(parent,
251a88b5ba8SSam Ravnborg 					"compatible", NULL);
252a88b5ba8SSam Ravnborg 	if (parent_compat &&
253a88b5ba8SSam Ravnborg 	    (!strcmp(parent_compat, "pci108e,a000") ||
254a88b5ba8SSam Ravnborg 	     !strcmp(parent_compat, "pci108e,a001")))
255a88b5ba8SSam Ravnborg 		return 0;
256a88b5ba8SSam Ravnborg 
257a88b5ba8SSam Ravnborg 	return 1;
258a88b5ba8SSam Ravnborg }
259a88b5ba8SSam Ravnborg 
260a88b5ba8SSam Ravnborg static unsigned int sabre_irq_build(struct device_node *dp,
261a88b5ba8SSam Ravnborg 				    unsigned int ino,
262a88b5ba8SSam Ravnborg 				    void *_data)
263a88b5ba8SSam Ravnborg {
264a88b5ba8SSam Ravnborg 	struct sabre_irq_data *irq_data = _data;
265a88b5ba8SSam Ravnborg 	unsigned long controller_regs = irq_data->controller_regs;
266a88b5ba8SSam Ravnborg 	const struct linux_prom_pci_registers *regs;
267a88b5ba8SSam Ravnborg 	unsigned long imap, iclr;
268a88b5ba8SSam Ravnborg 	unsigned long imap_off, iclr_off;
269a88b5ba8SSam Ravnborg 	int inofixup = 0;
270a88b5ba8SSam Ravnborg 	int virt_irq;
271a88b5ba8SSam Ravnborg 
272a88b5ba8SSam Ravnborg 	ino &= 0x3f;
273a88b5ba8SSam Ravnborg 	if (ino < SABRE_ONBOARD_IRQ_BASE) {
274a88b5ba8SSam Ravnborg 		/* PCI slot */
275a88b5ba8SSam Ravnborg 		imap_off = sabre_pcislot_imap_offset(ino);
276a88b5ba8SSam Ravnborg 	} else {
277a88b5ba8SSam Ravnborg 		/* onboard device */
278a88b5ba8SSam Ravnborg 		imap_off = sabre_onboard_imap_offset(ino);
279a88b5ba8SSam Ravnborg 	}
280a88b5ba8SSam Ravnborg 
281a88b5ba8SSam Ravnborg 	/* Now build the IRQ bucket. */
282a88b5ba8SSam Ravnborg 	imap = controller_regs + imap_off;
283a88b5ba8SSam Ravnborg 
284a88b5ba8SSam Ravnborg 	iclr_off = sabre_iclr_offset(ino);
285a88b5ba8SSam Ravnborg 	iclr = controller_regs + iclr_off;
286a88b5ba8SSam Ravnborg 
287a88b5ba8SSam Ravnborg 	if ((ino & 0x20) == 0)
288a88b5ba8SSam Ravnborg 		inofixup = ino & 0x03;
289a88b5ba8SSam Ravnborg 
290a88b5ba8SSam Ravnborg 	virt_irq = build_irq(inofixup, iclr, imap);
291a88b5ba8SSam Ravnborg 
292a88b5ba8SSam Ravnborg 	/* If the parent device is a PCI<->PCI bridge other than
293a88b5ba8SSam Ravnborg 	 * APB, we have to install a pre-handler to ensure that
294a88b5ba8SSam Ravnborg 	 * all pending DMA is drained before the interrupt handler
295a88b5ba8SSam Ravnborg 	 * is run.
296a88b5ba8SSam Ravnborg 	 */
297a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
298a88b5ba8SSam Ravnborg 	if (regs && sabre_device_needs_wsync(dp)) {
299a88b5ba8SSam Ravnborg 		irq_install_pre_handler(virt_irq,
300a88b5ba8SSam Ravnborg 					sabre_wsync_handler,
301a88b5ba8SSam Ravnborg 					(void *) (long) regs->phys_hi,
302a88b5ba8SSam Ravnborg 					(void *) irq_data);
303a88b5ba8SSam Ravnborg 	}
304a88b5ba8SSam Ravnborg 
305a88b5ba8SSam Ravnborg 	return virt_irq;
306a88b5ba8SSam Ravnborg }
307a88b5ba8SSam Ravnborg 
308a88b5ba8SSam Ravnborg static void __init sabre_irq_trans_init(struct device_node *dp)
309a88b5ba8SSam Ravnborg {
310a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
311a88b5ba8SSam Ravnborg 	struct sabre_irq_data *irq_data;
312a88b5ba8SSam Ravnborg 	const u32 *busrange;
313a88b5ba8SSam Ravnborg 
314a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
315a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = sabre_irq_build;
316a88b5ba8SSam Ravnborg 
317a88b5ba8SSam Ravnborg 	irq_data = prom_early_alloc(sizeof(struct sabre_irq_data));
318a88b5ba8SSam Ravnborg 
319a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
320a88b5ba8SSam Ravnborg 	irq_data->controller_regs = regs[0].phys_addr;
321a88b5ba8SSam Ravnborg 
322a88b5ba8SSam Ravnborg 	busrange = of_get_property(dp, "bus-range", NULL);
323a88b5ba8SSam Ravnborg 	irq_data->pci_first_busno = busrange[0];
324a88b5ba8SSam Ravnborg 
325a88b5ba8SSam Ravnborg 	dp->irq_trans->data = irq_data;
326a88b5ba8SSam Ravnborg }
327a88b5ba8SSam Ravnborg 
328a88b5ba8SSam Ravnborg /* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the
329a88b5ba8SSam Ravnborg  * imap/iclr registers are per-PBM.
330a88b5ba8SSam Ravnborg  */
331a88b5ba8SSam Ravnborg #define SCHIZO_IMAP_BASE	0x1000UL
332a88b5ba8SSam Ravnborg #define SCHIZO_ICLR_BASE	0x1400UL
333a88b5ba8SSam Ravnborg 
334a88b5ba8SSam Ravnborg static unsigned long schizo_imap_offset(unsigned long ino)
335a88b5ba8SSam Ravnborg {
336a88b5ba8SSam Ravnborg 	return SCHIZO_IMAP_BASE + (ino * 8UL);
337a88b5ba8SSam Ravnborg }
338a88b5ba8SSam Ravnborg 
339a88b5ba8SSam Ravnborg static unsigned long schizo_iclr_offset(unsigned long ino)
340a88b5ba8SSam Ravnborg {
341a88b5ba8SSam Ravnborg 	return SCHIZO_ICLR_BASE + (ino * 8UL);
342a88b5ba8SSam Ravnborg }
343a88b5ba8SSam Ravnborg 
344a88b5ba8SSam Ravnborg static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
345a88b5ba8SSam Ravnborg 					unsigned int ino)
346a88b5ba8SSam Ravnborg {
347a88b5ba8SSam Ravnborg 
348a88b5ba8SSam Ravnborg 	return pbm_regs + schizo_iclr_offset(ino);
349a88b5ba8SSam Ravnborg }
350a88b5ba8SSam Ravnborg 
351a88b5ba8SSam Ravnborg static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
352a88b5ba8SSam Ravnborg 					unsigned int ino)
353a88b5ba8SSam Ravnborg {
354a88b5ba8SSam Ravnborg 	return pbm_regs + schizo_imap_offset(ino);
355a88b5ba8SSam Ravnborg }
356a88b5ba8SSam Ravnborg 
357a88b5ba8SSam Ravnborg #define schizo_read(__reg) \
358a88b5ba8SSam Ravnborg ({	u64 __ret; \
359a88b5ba8SSam Ravnborg 	__asm__ __volatile__("ldxa [%1] %2, %0" \
360a88b5ba8SSam Ravnborg 			     : "=r" (__ret) \
361a88b5ba8SSam Ravnborg 			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
362a88b5ba8SSam Ravnborg 			     : "memory"); \
363a88b5ba8SSam Ravnborg 	__ret; \
364a88b5ba8SSam Ravnborg })
365a88b5ba8SSam Ravnborg #define schizo_write(__reg, __val) \
366a88b5ba8SSam Ravnborg 	__asm__ __volatile__("stxa %0, [%1] %2" \
367a88b5ba8SSam Ravnborg 			     : /* no outputs */ \
368a88b5ba8SSam Ravnborg 			     : "r" (__val), "r" (__reg), \
369a88b5ba8SSam Ravnborg 			       "i" (ASI_PHYS_BYPASS_EC_E) \
370a88b5ba8SSam Ravnborg 			     : "memory")
371a88b5ba8SSam Ravnborg 
372a88b5ba8SSam Ravnborg static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
373a88b5ba8SSam Ravnborg {
374a88b5ba8SSam Ravnborg 	unsigned long sync_reg = (unsigned long) _arg2;
375a88b5ba8SSam Ravnborg 	u64 mask = 1UL << (ino & IMAP_INO);
376a88b5ba8SSam Ravnborg 	u64 val;
377a88b5ba8SSam Ravnborg 	int limit;
378a88b5ba8SSam Ravnborg 
379a88b5ba8SSam Ravnborg 	schizo_write(sync_reg, mask);
380a88b5ba8SSam Ravnborg 
381a88b5ba8SSam Ravnborg 	limit = 100000;
382a88b5ba8SSam Ravnborg 	val = 0;
383a88b5ba8SSam Ravnborg 	while (--limit) {
384a88b5ba8SSam Ravnborg 		val = schizo_read(sync_reg);
385a88b5ba8SSam Ravnborg 		if (!(val & mask))
386a88b5ba8SSam Ravnborg 			break;
387a88b5ba8SSam Ravnborg 	}
388a88b5ba8SSam Ravnborg 	if (limit <= 0) {
389a88b5ba8SSam Ravnborg 		printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n",
390a88b5ba8SSam Ravnborg 		       val, mask);
391a88b5ba8SSam Ravnborg 	}
392a88b5ba8SSam Ravnborg 
393a88b5ba8SSam Ravnborg 	if (_arg1) {
394a88b5ba8SSam Ravnborg 		static unsigned char cacheline[64]
395a88b5ba8SSam Ravnborg 			__attribute__ ((aligned (64)));
396a88b5ba8SSam Ravnborg 
397a88b5ba8SSam Ravnborg 		__asm__ __volatile__("rd %%fprs, %0\n\t"
398a88b5ba8SSam Ravnborg 				     "or %0, %4, %1\n\t"
399a88b5ba8SSam Ravnborg 				     "wr %1, 0x0, %%fprs\n\t"
400a88b5ba8SSam Ravnborg 				     "stda %%f0, [%5] %6\n\t"
401a88b5ba8SSam Ravnborg 				     "wr %0, 0x0, %%fprs\n\t"
402a88b5ba8SSam Ravnborg 				     "membar #Sync"
403a88b5ba8SSam Ravnborg 				     : "=&r" (mask), "=&r" (val)
404a88b5ba8SSam Ravnborg 				     : "0" (mask), "1" (val),
405a88b5ba8SSam Ravnborg 				     "i" (FPRS_FEF), "r" (&cacheline[0]),
406a88b5ba8SSam Ravnborg 				     "i" (ASI_BLK_COMMIT_P));
407a88b5ba8SSam Ravnborg 	}
408a88b5ba8SSam Ravnborg }
409a88b5ba8SSam Ravnborg 
410a88b5ba8SSam Ravnborg struct schizo_irq_data {
411a88b5ba8SSam Ravnborg 	unsigned long pbm_regs;
412a88b5ba8SSam Ravnborg 	unsigned long sync_reg;
413a88b5ba8SSam Ravnborg 	u32 portid;
414a88b5ba8SSam Ravnborg 	int chip_version;
415a88b5ba8SSam Ravnborg };
416a88b5ba8SSam Ravnborg 
417a88b5ba8SSam Ravnborg static unsigned int schizo_irq_build(struct device_node *dp,
418a88b5ba8SSam Ravnborg 				     unsigned int ino,
419a88b5ba8SSam Ravnborg 				     void *_data)
420a88b5ba8SSam Ravnborg {
421a88b5ba8SSam Ravnborg 	struct schizo_irq_data *irq_data = _data;
422a88b5ba8SSam Ravnborg 	unsigned long pbm_regs = irq_data->pbm_regs;
423a88b5ba8SSam Ravnborg 	unsigned long imap, iclr;
424a88b5ba8SSam Ravnborg 	int ign_fixup;
425a88b5ba8SSam Ravnborg 	int virt_irq;
426a88b5ba8SSam Ravnborg 	int is_tomatillo;
427a88b5ba8SSam Ravnborg 
428a88b5ba8SSam Ravnborg 	ino &= 0x3f;
429a88b5ba8SSam Ravnborg 
430a88b5ba8SSam Ravnborg 	/* Now build the IRQ bucket. */
431a88b5ba8SSam Ravnborg 	imap = schizo_ino_to_imap(pbm_regs, ino);
432a88b5ba8SSam Ravnborg 	iclr = schizo_ino_to_iclr(pbm_regs, ino);
433a88b5ba8SSam Ravnborg 
434a88b5ba8SSam Ravnborg 	/* On Schizo, no inofixup occurs.  This is because each
435a88b5ba8SSam Ravnborg 	 * INO has it's own IMAP register.  On Psycho and Sabre
436a88b5ba8SSam Ravnborg 	 * there is only one IMAP register for each PCI slot even
437a88b5ba8SSam Ravnborg 	 * though four different INOs can be generated by each
438a88b5ba8SSam Ravnborg 	 * PCI slot.
439a88b5ba8SSam Ravnborg 	 *
440a88b5ba8SSam Ravnborg 	 * But, for JBUS variants (essentially, Tomatillo), we have
441a88b5ba8SSam Ravnborg 	 * to fixup the lowest bit of the interrupt group number.
442a88b5ba8SSam Ravnborg 	 */
443a88b5ba8SSam Ravnborg 	ign_fixup = 0;
444a88b5ba8SSam Ravnborg 
445a88b5ba8SSam Ravnborg 	is_tomatillo = (irq_data->sync_reg != 0UL);
446a88b5ba8SSam Ravnborg 
447a88b5ba8SSam Ravnborg 	if (is_tomatillo) {
448a88b5ba8SSam Ravnborg 		if (irq_data->portid & 1)
449a88b5ba8SSam Ravnborg 			ign_fixup = (1 << 6);
450a88b5ba8SSam Ravnborg 	}
451a88b5ba8SSam Ravnborg 
452a88b5ba8SSam Ravnborg 	virt_irq = build_irq(ign_fixup, iclr, imap);
453a88b5ba8SSam Ravnborg 
454a88b5ba8SSam Ravnborg 	if (is_tomatillo) {
455a88b5ba8SSam Ravnborg 		irq_install_pre_handler(virt_irq,
456a88b5ba8SSam Ravnborg 					tomatillo_wsync_handler,
457a88b5ba8SSam Ravnborg 					((irq_data->chip_version <= 4) ?
458a88b5ba8SSam Ravnborg 					 (void *) 1 : (void *) 0),
459a88b5ba8SSam Ravnborg 					(void *) irq_data->sync_reg);
460a88b5ba8SSam Ravnborg 	}
461a88b5ba8SSam Ravnborg 
462a88b5ba8SSam Ravnborg 	return virt_irq;
463a88b5ba8SSam Ravnborg }
464a88b5ba8SSam Ravnborg 
465a88b5ba8SSam Ravnborg static void __init __schizo_irq_trans_init(struct device_node *dp,
466a88b5ba8SSam Ravnborg 					   int is_tomatillo)
467a88b5ba8SSam Ravnborg {
468a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
469a88b5ba8SSam Ravnborg 	struct schizo_irq_data *irq_data;
470a88b5ba8SSam Ravnborg 
471a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
472a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = schizo_irq_build;
473a88b5ba8SSam Ravnborg 
474a88b5ba8SSam Ravnborg 	irq_data = prom_early_alloc(sizeof(struct schizo_irq_data));
475a88b5ba8SSam Ravnborg 
476a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
477a88b5ba8SSam Ravnborg 	dp->irq_trans->data = irq_data;
478a88b5ba8SSam Ravnborg 
479a88b5ba8SSam Ravnborg 	irq_data->pbm_regs = regs[0].phys_addr;
480a88b5ba8SSam Ravnborg 	if (is_tomatillo)
481a88b5ba8SSam Ravnborg 		irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
482a88b5ba8SSam Ravnborg 	else
483a88b5ba8SSam Ravnborg 		irq_data->sync_reg = 0UL;
484a88b5ba8SSam Ravnborg 	irq_data->portid = of_getintprop_default(dp, "portid", 0);
485a88b5ba8SSam Ravnborg 	irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
486a88b5ba8SSam Ravnborg }
487a88b5ba8SSam Ravnborg 
488a88b5ba8SSam Ravnborg static void __init schizo_irq_trans_init(struct device_node *dp)
489a88b5ba8SSam Ravnborg {
490a88b5ba8SSam Ravnborg 	__schizo_irq_trans_init(dp, 0);
491a88b5ba8SSam Ravnborg }
492a88b5ba8SSam Ravnborg 
493a88b5ba8SSam Ravnborg static void __init tomatillo_irq_trans_init(struct device_node *dp)
494a88b5ba8SSam Ravnborg {
495a88b5ba8SSam Ravnborg 	__schizo_irq_trans_init(dp, 1);
496a88b5ba8SSam Ravnborg }
497a88b5ba8SSam Ravnborg 
498a88b5ba8SSam Ravnborg static unsigned int pci_sun4v_irq_build(struct device_node *dp,
499a88b5ba8SSam Ravnborg 					unsigned int devino,
500a88b5ba8SSam Ravnborg 					void *_data)
501a88b5ba8SSam Ravnborg {
502a88b5ba8SSam Ravnborg 	u32 devhandle = (u32) (unsigned long) _data;
503a88b5ba8SSam Ravnborg 
504a88b5ba8SSam Ravnborg 	return sun4v_build_irq(devhandle, devino);
505a88b5ba8SSam Ravnborg }
506a88b5ba8SSam Ravnborg 
507a88b5ba8SSam Ravnborg static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
508a88b5ba8SSam Ravnborg {
509a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
510a88b5ba8SSam Ravnborg 
511a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
512a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = pci_sun4v_irq_build;
513a88b5ba8SSam Ravnborg 
514a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
515a88b5ba8SSam Ravnborg 	dp->irq_trans->data = (void *) (unsigned long)
516a88b5ba8SSam Ravnborg 		((regs->phys_addr >> 32UL) & 0x0fffffff);
517a88b5ba8SSam Ravnborg }
518a88b5ba8SSam Ravnborg 
519a88b5ba8SSam Ravnborg struct fire_irq_data {
520a88b5ba8SSam Ravnborg 	unsigned long pbm_regs;
521a88b5ba8SSam Ravnborg 	u32 portid;
522a88b5ba8SSam Ravnborg };
523a88b5ba8SSam Ravnborg 
524a88b5ba8SSam Ravnborg #define FIRE_IMAP_BASE	0x001000
525a88b5ba8SSam Ravnborg #define FIRE_ICLR_BASE	0x001400
526a88b5ba8SSam Ravnborg 
527a88b5ba8SSam Ravnborg static unsigned long fire_imap_offset(unsigned long ino)
528a88b5ba8SSam Ravnborg {
529a88b5ba8SSam Ravnborg 	return FIRE_IMAP_BASE + (ino * 8UL);
530a88b5ba8SSam Ravnborg }
531a88b5ba8SSam Ravnborg 
532a88b5ba8SSam Ravnborg static unsigned long fire_iclr_offset(unsigned long ino)
533a88b5ba8SSam Ravnborg {
534a88b5ba8SSam Ravnborg 	return FIRE_ICLR_BASE + (ino * 8UL);
535a88b5ba8SSam Ravnborg }
536a88b5ba8SSam Ravnborg 
537a88b5ba8SSam Ravnborg static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
538a88b5ba8SSam Ravnborg 					    unsigned int ino)
539a88b5ba8SSam Ravnborg {
540a88b5ba8SSam Ravnborg 	return pbm_regs + fire_iclr_offset(ino);
541a88b5ba8SSam Ravnborg }
542a88b5ba8SSam Ravnborg 
543a88b5ba8SSam Ravnborg static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
544a88b5ba8SSam Ravnborg 					    unsigned int ino)
545a88b5ba8SSam Ravnborg {
546a88b5ba8SSam Ravnborg 	return pbm_regs + fire_imap_offset(ino);
547a88b5ba8SSam Ravnborg }
548a88b5ba8SSam Ravnborg 
549a88b5ba8SSam Ravnborg static unsigned int fire_irq_build(struct device_node *dp,
550a88b5ba8SSam Ravnborg 					 unsigned int ino,
551a88b5ba8SSam Ravnborg 					 void *_data)
552a88b5ba8SSam Ravnborg {
553a88b5ba8SSam Ravnborg 	struct fire_irq_data *irq_data = _data;
554a88b5ba8SSam Ravnborg 	unsigned long pbm_regs = irq_data->pbm_regs;
555a88b5ba8SSam Ravnborg 	unsigned long imap, iclr;
556a88b5ba8SSam Ravnborg 	unsigned long int_ctrlr;
557a88b5ba8SSam Ravnborg 
558a88b5ba8SSam Ravnborg 	ino &= 0x3f;
559a88b5ba8SSam Ravnborg 
560a88b5ba8SSam Ravnborg 	/* Now build the IRQ bucket. */
561a88b5ba8SSam Ravnborg 	imap = fire_ino_to_imap(pbm_regs, ino);
562a88b5ba8SSam Ravnborg 	iclr = fire_ino_to_iclr(pbm_regs, ino);
563a88b5ba8SSam Ravnborg 
564a88b5ba8SSam Ravnborg 	/* Set the interrupt controller number.  */
565a88b5ba8SSam Ravnborg 	int_ctrlr = 1 << 6;
566a88b5ba8SSam Ravnborg 	upa_writeq(int_ctrlr, imap);
567a88b5ba8SSam Ravnborg 
568a88b5ba8SSam Ravnborg 	/* The interrupt map registers do not have an INO field
569a88b5ba8SSam Ravnborg 	 * like other chips do.  They return zero in the INO
570a88b5ba8SSam Ravnborg 	 * field, and the interrupt controller number is controlled
571a88b5ba8SSam Ravnborg 	 * in bits 6 to 9.  So in order for build_irq() to get
572a88b5ba8SSam Ravnborg 	 * the INO right we pass it in as part of the fixup
573a88b5ba8SSam Ravnborg 	 * which will get added to the map register zero value
574a88b5ba8SSam Ravnborg 	 * read by build_irq().
575a88b5ba8SSam Ravnborg 	 */
576a88b5ba8SSam Ravnborg 	ino |= (irq_data->portid << 6);
577a88b5ba8SSam Ravnborg 	ino -= int_ctrlr;
578a88b5ba8SSam Ravnborg 	return build_irq(ino, iclr, imap);
579a88b5ba8SSam Ravnborg }
580a88b5ba8SSam Ravnborg 
581a88b5ba8SSam Ravnborg static void __init fire_irq_trans_init(struct device_node *dp)
582a88b5ba8SSam Ravnborg {
583a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
584a88b5ba8SSam Ravnborg 	struct fire_irq_data *irq_data;
585a88b5ba8SSam Ravnborg 
586a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
587a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = fire_irq_build;
588a88b5ba8SSam Ravnborg 
589a88b5ba8SSam Ravnborg 	irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
590a88b5ba8SSam Ravnborg 
591a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
592a88b5ba8SSam Ravnborg 	dp->irq_trans->data = irq_data;
593a88b5ba8SSam Ravnborg 
594a88b5ba8SSam Ravnborg 	irq_data->pbm_regs = regs[0].phys_addr;
595a88b5ba8SSam Ravnborg 	irq_data->portid = of_getintprop_default(dp, "portid", 0);
596a88b5ba8SSam Ravnborg }
597a88b5ba8SSam Ravnborg #endif /* CONFIG_PCI */
598a88b5ba8SSam Ravnborg 
599a88b5ba8SSam Ravnborg #ifdef CONFIG_SBUS
600a88b5ba8SSam Ravnborg /* INO number to IMAP register offset for SYSIO external IRQ's.
601a88b5ba8SSam Ravnborg  * This should conform to both Sunfire/Wildfire server and Fusion
602a88b5ba8SSam Ravnborg  * desktop designs.
603a88b5ba8SSam Ravnborg  */
604a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT0	0x2c00UL
605a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT1	0x2c08UL
606a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT2	0x2c10UL
607a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SLOT3	0x2c18UL
608a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SCSI		0x3000UL
609a88b5ba8SSam Ravnborg #define SYSIO_IMAP_ETH		0x3008UL
610a88b5ba8SSam Ravnborg #define SYSIO_IMAP_BPP		0x3010UL
611a88b5ba8SSam Ravnborg #define SYSIO_IMAP_AUDIO	0x3018UL
612a88b5ba8SSam Ravnborg #define SYSIO_IMAP_PFAIL	0x3020UL
613a88b5ba8SSam Ravnborg #define SYSIO_IMAP_KMS		0x3028UL
614a88b5ba8SSam Ravnborg #define SYSIO_IMAP_FLPY		0x3030UL
615a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SHW		0x3038UL
616a88b5ba8SSam Ravnborg #define SYSIO_IMAP_KBD		0x3040UL
617a88b5ba8SSam Ravnborg #define SYSIO_IMAP_MS		0x3048UL
618a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SER		0x3050UL
619a88b5ba8SSam Ravnborg #define SYSIO_IMAP_TIM0		0x3060UL
620a88b5ba8SSam Ravnborg #define SYSIO_IMAP_TIM1		0x3068UL
621a88b5ba8SSam Ravnborg #define SYSIO_IMAP_UE		0x3070UL
622a88b5ba8SSam Ravnborg #define SYSIO_IMAP_CE		0x3078UL
623a88b5ba8SSam Ravnborg #define SYSIO_IMAP_SBERR	0x3080UL
624a88b5ba8SSam Ravnborg #define SYSIO_IMAP_PMGMT	0x3088UL
625a88b5ba8SSam Ravnborg #define SYSIO_IMAP_GFX		0x3090UL
626a88b5ba8SSam Ravnborg #define SYSIO_IMAP_EUPA		0x3098UL
627a88b5ba8SSam Ravnborg 
628a88b5ba8SSam Ravnborg #define bogon     ((unsigned long) -1)
629a88b5ba8SSam Ravnborg static unsigned long sysio_irq_offsets[] = {
630a88b5ba8SSam Ravnborg 	/* SBUS Slot 0 --> 3, level 1 --> 7 */
631a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
632a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
633a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
634a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
635a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
636a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
637a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
638a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
639a88b5ba8SSam Ravnborg 
640a88b5ba8SSam Ravnborg 	/* Onboard devices (not relevant/used on SunFire). */
641a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SCSI,
642a88b5ba8SSam Ravnborg 	SYSIO_IMAP_ETH,
643a88b5ba8SSam Ravnborg 	SYSIO_IMAP_BPP,
644a88b5ba8SSam Ravnborg 	bogon,
645a88b5ba8SSam Ravnborg 	SYSIO_IMAP_AUDIO,
646a88b5ba8SSam Ravnborg 	SYSIO_IMAP_PFAIL,
647a88b5ba8SSam Ravnborg 	bogon,
648a88b5ba8SSam Ravnborg 	bogon,
649a88b5ba8SSam Ravnborg 	SYSIO_IMAP_KMS,
650a88b5ba8SSam Ravnborg 	SYSIO_IMAP_FLPY,
651a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SHW,
652a88b5ba8SSam Ravnborg 	SYSIO_IMAP_KBD,
653a88b5ba8SSam Ravnborg 	SYSIO_IMAP_MS,
654a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SER,
655a88b5ba8SSam Ravnborg 	bogon,
656a88b5ba8SSam Ravnborg 	bogon,
657a88b5ba8SSam Ravnborg 	SYSIO_IMAP_TIM0,
658a88b5ba8SSam Ravnborg 	SYSIO_IMAP_TIM1,
659a88b5ba8SSam Ravnborg 	bogon,
660a88b5ba8SSam Ravnborg 	bogon,
661a88b5ba8SSam Ravnborg 	SYSIO_IMAP_UE,
662a88b5ba8SSam Ravnborg 	SYSIO_IMAP_CE,
663a88b5ba8SSam Ravnborg 	SYSIO_IMAP_SBERR,
664a88b5ba8SSam Ravnborg 	SYSIO_IMAP_PMGMT,
665a88b5ba8SSam Ravnborg 	SYSIO_IMAP_GFX,
666a88b5ba8SSam Ravnborg 	SYSIO_IMAP_EUPA,
667a88b5ba8SSam Ravnborg };
668a88b5ba8SSam Ravnborg 
669a88b5ba8SSam Ravnborg #undef bogon
670a88b5ba8SSam Ravnborg 
671a88b5ba8SSam Ravnborg #define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
672a88b5ba8SSam Ravnborg 
673a88b5ba8SSam Ravnborg /* Convert Interrupt Mapping register pointer to associated
674a88b5ba8SSam Ravnborg  * Interrupt Clear register pointer, SYSIO specific version.
675a88b5ba8SSam Ravnborg  */
676a88b5ba8SSam Ravnborg #define SYSIO_ICLR_UNUSED0	0x3400UL
677a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT0	0x3408UL
678a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT1	0x3448UL
679a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT2	0x3488UL
680a88b5ba8SSam Ravnborg #define SYSIO_ICLR_SLOT3	0x34c8UL
681a88b5ba8SSam Ravnborg static unsigned long sysio_imap_to_iclr(unsigned long imap)
682a88b5ba8SSam Ravnborg {
683a88b5ba8SSam Ravnborg 	unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
684a88b5ba8SSam Ravnborg 	return imap + diff;
685a88b5ba8SSam Ravnborg }
686a88b5ba8SSam Ravnborg 
687a88b5ba8SSam Ravnborg static unsigned int sbus_of_build_irq(struct device_node *dp,
688a88b5ba8SSam Ravnborg 				      unsigned int ino,
689a88b5ba8SSam Ravnborg 				      void *_data)
690a88b5ba8SSam Ravnborg {
691a88b5ba8SSam Ravnborg 	unsigned long reg_base = (unsigned long) _data;
692a88b5ba8SSam Ravnborg 	const struct linux_prom_registers *regs;
693a88b5ba8SSam Ravnborg 	unsigned long imap, iclr;
694a88b5ba8SSam Ravnborg 	int sbus_slot = 0;
695a88b5ba8SSam Ravnborg 	int sbus_level = 0;
696a88b5ba8SSam Ravnborg 
697a88b5ba8SSam Ravnborg 	ino &= 0x3f;
698a88b5ba8SSam Ravnborg 
699a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
700a88b5ba8SSam Ravnborg 	if (regs)
701a88b5ba8SSam Ravnborg 		sbus_slot = regs->which_io;
702a88b5ba8SSam Ravnborg 
703a88b5ba8SSam Ravnborg 	if (ino < 0x20)
704a88b5ba8SSam Ravnborg 		ino += (sbus_slot * 8);
705a88b5ba8SSam Ravnborg 
706a88b5ba8SSam Ravnborg 	imap = sysio_irq_offsets[ino];
707a88b5ba8SSam Ravnborg 	if (imap == ((unsigned long)-1)) {
708a88b5ba8SSam Ravnborg 		prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
709a88b5ba8SSam Ravnborg 			    ino);
710a88b5ba8SSam Ravnborg 		prom_halt();
711a88b5ba8SSam Ravnborg 	}
712a88b5ba8SSam Ravnborg 	imap += reg_base;
713a88b5ba8SSam Ravnborg 
714a88b5ba8SSam Ravnborg 	/* SYSIO inconsistency.  For external SLOTS, we have to select
715a88b5ba8SSam Ravnborg 	 * the right ICLR register based upon the lower SBUS irq level
716a88b5ba8SSam Ravnborg 	 * bits.
717a88b5ba8SSam Ravnborg 	 */
718a88b5ba8SSam Ravnborg 	if (ino >= 0x20) {
719a88b5ba8SSam Ravnborg 		iclr = sysio_imap_to_iclr(imap);
720a88b5ba8SSam Ravnborg 	} else {
721a88b5ba8SSam Ravnborg 		sbus_level = ino & 0x7;
722a88b5ba8SSam Ravnborg 
723a88b5ba8SSam Ravnborg 		switch(sbus_slot) {
724a88b5ba8SSam Ravnborg 		case 0:
725a88b5ba8SSam Ravnborg 			iclr = reg_base + SYSIO_ICLR_SLOT0;
726a88b5ba8SSam Ravnborg 			break;
727a88b5ba8SSam Ravnborg 		case 1:
728a88b5ba8SSam Ravnborg 			iclr = reg_base + SYSIO_ICLR_SLOT1;
729a88b5ba8SSam Ravnborg 			break;
730a88b5ba8SSam Ravnborg 		case 2:
731a88b5ba8SSam Ravnborg 			iclr = reg_base + SYSIO_ICLR_SLOT2;
732a88b5ba8SSam Ravnborg 			break;
733a88b5ba8SSam Ravnborg 		default:
734a88b5ba8SSam Ravnborg 		case 3:
735a88b5ba8SSam Ravnborg 			iclr = reg_base + SYSIO_ICLR_SLOT3;
736a88b5ba8SSam Ravnborg 			break;
737a88b5ba8SSam Ravnborg 		};
738a88b5ba8SSam Ravnborg 
739a88b5ba8SSam Ravnborg 		iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
740a88b5ba8SSam Ravnborg 	}
741a88b5ba8SSam Ravnborg 	return build_irq(sbus_level, iclr, imap);
742a88b5ba8SSam Ravnborg }
743a88b5ba8SSam Ravnborg 
744a88b5ba8SSam Ravnborg static void __init sbus_irq_trans_init(struct device_node *dp)
745a88b5ba8SSam Ravnborg {
746a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
747a88b5ba8SSam Ravnborg 
748a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
749a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = sbus_of_build_irq;
750a88b5ba8SSam Ravnborg 
751a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
752a88b5ba8SSam Ravnborg 	dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr;
753a88b5ba8SSam Ravnborg }
754a88b5ba8SSam Ravnborg #endif /* CONFIG_SBUS */
755a88b5ba8SSam Ravnborg 
756a88b5ba8SSam Ravnborg 
757a88b5ba8SSam Ravnborg static unsigned int central_build_irq(struct device_node *dp,
758a88b5ba8SSam Ravnborg 				      unsigned int ino,
759a88b5ba8SSam Ravnborg 				      void *_data)
760a88b5ba8SSam Ravnborg {
761a88b5ba8SSam Ravnborg 	struct device_node *central_dp = _data;
762a88b5ba8SSam Ravnborg 	struct of_device *central_op = of_find_device_by_node(central_dp);
763a88b5ba8SSam Ravnborg 	struct resource *res;
764a88b5ba8SSam Ravnborg 	unsigned long imap, iclr;
765a88b5ba8SSam Ravnborg 	u32 tmp;
766a88b5ba8SSam Ravnborg 
767a88b5ba8SSam Ravnborg 	if (!strcmp(dp->name, "eeprom")) {
768a88b5ba8SSam Ravnborg 		res = &central_op->resource[5];
769a88b5ba8SSam Ravnborg 	} else if (!strcmp(dp->name, "zs")) {
770a88b5ba8SSam Ravnborg 		res = &central_op->resource[4];
771a88b5ba8SSam Ravnborg 	} else if (!strcmp(dp->name, "clock-board")) {
772a88b5ba8SSam Ravnborg 		res = &central_op->resource[3];
773a88b5ba8SSam Ravnborg 	} else {
774a88b5ba8SSam Ravnborg 		return ino;
775a88b5ba8SSam Ravnborg 	}
776a88b5ba8SSam Ravnborg 
777a88b5ba8SSam Ravnborg 	imap = res->start + 0x00UL;
778a88b5ba8SSam Ravnborg 	iclr = res->start + 0x10UL;
779a88b5ba8SSam Ravnborg 
780a88b5ba8SSam Ravnborg 	/* Set the INO state to idle, and disable.  */
781a88b5ba8SSam Ravnborg 	upa_writel(0, iclr);
782a88b5ba8SSam Ravnborg 	upa_readl(iclr);
783a88b5ba8SSam Ravnborg 
784a88b5ba8SSam Ravnborg 	tmp = upa_readl(imap);
785a88b5ba8SSam Ravnborg 	tmp &= ~0x80000000;
786a88b5ba8SSam Ravnborg 	upa_writel(tmp, imap);
787a88b5ba8SSam Ravnborg 
788a88b5ba8SSam Ravnborg 	return build_irq(0, iclr, imap);
789a88b5ba8SSam Ravnborg }
790a88b5ba8SSam Ravnborg 
791a88b5ba8SSam Ravnborg static void __init central_irq_trans_init(struct device_node *dp)
792a88b5ba8SSam Ravnborg {
793a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
794a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = central_build_irq;
795a88b5ba8SSam Ravnborg 
796a88b5ba8SSam Ravnborg 	dp->irq_trans->data = dp;
797a88b5ba8SSam Ravnborg }
798a88b5ba8SSam Ravnborg 
799a88b5ba8SSam Ravnborg struct irq_trans {
800a88b5ba8SSam Ravnborg 	const char *name;
801a88b5ba8SSam Ravnborg 	void (*init)(struct device_node *);
802a88b5ba8SSam Ravnborg };
803a88b5ba8SSam Ravnborg 
804a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI
805a88b5ba8SSam Ravnborg static struct irq_trans __initdata pci_irq_trans_table[] = {
806a88b5ba8SSam Ravnborg 	{ "SUNW,sabre", sabre_irq_trans_init },
807a88b5ba8SSam Ravnborg 	{ "pci108e,a000", sabre_irq_trans_init },
808a88b5ba8SSam Ravnborg 	{ "pci108e,a001", sabre_irq_trans_init },
809a88b5ba8SSam Ravnborg 	{ "SUNW,psycho", psycho_irq_trans_init },
810a88b5ba8SSam Ravnborg 	{ "pci108e,8000", psycho_irq_trans_init },
811a88b5ba8SSam Ravnborg 	{ "SUNW,schizo", schizo_irq_trans_init },
812a88b5ba8SSam Ravnborg 	{ "pci108e,8001", schizo_irq_trans_init },
813a88b5ba8SSam Ravnborg 	{ "SUNW,schizo+", schizo_irq_trans_init },
814a88b5ba8SSam Ravnborg 	{ "pci108e,8002", schizo_irq_trans_init },
815a88b5ba8SSam Ravnborg 	{ "SUNW,tomatillo", tomatillo_irq_trans_init },
816a88b5ba8SSam Ravnborg 	{ "pci108e,a801", tomatillo_irq_trans_init },
817a88b5ba8SSam Ravnborg 	{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
818a88b5ba8SSam Ravnborg 	{ "pciex108e,80f0", fire_irq_trans_init },
819a88b5ba8SSam Ravnborg };
820a88b5ba8SSam Ravnborg #endif
821a88b5ba8SSam Ravnborg 
822a88b5ba8SSam Ravnborg static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
823a88b5ba8SSam Ravnborg 					 unsigned int devino,
824a88b5ba8SSam Ravnborg 					 void *_data)
825a88b5ba8SSam Ravnborg {
826a88b5ba8SSam Ravnborg 	u32 devhandle = (u32) (unsigned long) _data;
827a88b5ba8SSam Ravnborg 
828a88b5ba8SSam Ravnborg 	return sun4v_build_irq(devhandle, devino);
829a88b5ba8SSam Ravnborg }
830a88b5ba8SSam Ravnborg 
831a88b5ba8SSam Ravnborg static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
832a88b5ba8SSam Ravnborg {
833a88b5ba8SSam Ravnborg 	const struct linux_prom64_registers *regs;
834a88b5ba8SSam Ravnborg 
835a88b5ba8SSam Ravnborg 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
836a88b5ba8SSam Ravnborg 	dp->irq_trans->irq_build = sun4v_vdev_irq_build;
837a88b5ba8SSam Ravnborg 
838a88b5ba8SSam Ravnborg 	regs = of_get_property(dp, "reg", NULL);
839a88b5ba8SSam Ravnborg 	dp->irq_trans->data = (void *) (unsigned long)
840a88b5ba8SSam Ravnborg 		((regs->phys_addr >> 32UL) & 0x0fffffff);
841a88b5ba8SSam Ravnborg }
842a88b5ba8SSam Ravnborg 
843a88b5ba8SSam Ravnborg static void __init irq_trans_init(struct device_node *dp)
844a88b5ba8SSam Ravnborg {
845a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI
846a88b5ba8SSam Ravnborg 	const char *model;
847a88b5ba8SSam Ravnborg 	int i;
848a88b5ba8SSam Ravnborg #endif
849a88b5ba8SSam Ravnborg 
850a88b5ba8SSam Ravnborg #ifdef CONFIG_PCI
851a88b5ba8SSam Ravnborg 	model = of_get_property(dp, "model", NULL);
852a88b5ba8SSam Ravnborg 	if (!model)
853a88b5ba8SSam Ravnborg 		model = of_get_property(dp, "compatible", NULL);
854a88b5ba8SSam Ravnborg 	if (model) {
855a88b5ba8SSam Ravnborg 		for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
856a88b5ba8SSam Ravnborg 			struct irq_trans *t = &pci_irq_trans_table[i];
857a88b5ba8SSam Ravnborg 
858a88b5ba8SSam Ravnborg 			if (!strcmp(model, t->name)) {
859a88b5ba8SSam Ravnborg 				t->init(dp);
860a88b5ba8SSam Ravnborg 				return;
861a88b5ba8SSam Ravnborg 			}
862a88b5ba8SSam Ravnborg 		}
863a88b5ba8SSam Ravnborg 	}
864a88b5ba8SSam Ravnborg #endif
865a88b5ba8SSam Ravnborg #ifdef CONFIG_SBUS
866a88b5ba8SSam Ravnborg 	if (!strcmp(dp->name, "sbus") ||
867a88b5ba8SSam Ravnborg 	    !strcmp(dp->name, "sbi")) {
868a88b5ba8SSam Ravnborg 		sbus_irq_trans_init(dp);
869a88b5ba8SSam Ravnborg 		return;
870a88b5ba8SSam Ravnborg 	}
871a88b5ba8SSam Ravnborg #endif
872a88b5ba8SSam Ravnborg 	if (!strcmp(dp->name, "fhc") &&
873a88b5ba8SSam Ravnborg 	    !strcmp(dp->parent->name, "central")) {
874a88b5ba8SSam Ravnborg 		central_irq_trans_init(dp);
875a88b5ba8SSam Ravnborg 		return;
876a88b5ba8SSam Ravnborg 	}
877a88b5ba8SSam Ravnborg 	if (!strcmp(dp->name, "virtual-devices") ||
878a88b5ba8SSam Ravnborg 	    !strcmp(dp->name, "niu")) {
879a88b5ba8SSam Ravnborg 		sun4v_vdev_irq_trans_init(dp);
880a88b5ba8SSam Ravnborg 		return;
881a88b5ba8SSam Ravnborg 	}
882a88b5ba8SSam Ravnborg }
883a88b5ba8SSam Ravnborg 
884a88b5ba8SSam Ravnborg static int is_root_node(const struct device_node *dp)
885a88b5ba8SSam Ravnborg {
886a88b5ba8SSam Ravnborg 	if (!dp)
887a88b5ba8SSam Ravnborg 		return 0;
888a88b5ba8SSam Ravnborg 
889a88b5ba8SSam Ravnborg 	return (dp->parent == NULL);
890a88b5ba8SSam Ravnborg }
891a88b5ba8SSam Ravnborg 
892a88b5ba8SSam Ravnborg /* The following routines deal with the black magic of fully naming a
893a88b5ba8SSam Ravnborg  * node.
894a88b5ba8SSam Ravnborg  *
895a88b5ba8SSam Ravnborg  * Certain well known named nodes are just the simple name string.
896a88b5ba8SSam Ravnborg  *
897a88b5ba8SSam Ravnborg  * Actual devices have an address specifier appended to the base name
898a88b5ba8SSam Ravnborg  * string, like this "foo@addr".  The "addr" can be in any number of
899a88b5ba8SSam Ravnborg  * formats, and the platform plus the type of the node determine the
900a88b5ba8SSam Ravnborg  * format and how it is constructed.
901a88b5ba8SSam Ravnborg  *
902a88b5ba8SSam Ravnborg  * For children of the ROOT node, the naming convention is fixed and
903a88b5ba8SSam Ravnborg  * determined by whether this is a sun4u or sun4v system.
904a88b5ba8SSam Ravnborg  *
905a88b5ba8SSam Ravnborg  * For children of other nodes, it is bus type specific.  So
906a88b5ba8SSam Ravnborg  * we walk up the tree until we discover a "device_type" property
907a88b5ba8SSam Ravnborg  * we recognize and we go from there.
908a88b5ba8SSam Ravnborg  *
909a88b5ba8SSam Ravnborg  * As an example, the boot device on my workstation has a full path:
910a88b5ba8SSam Ravnborg  *
911a88b5ba8SSam Ravnborg  *	/pci@1e,600000/ide@d/disk@0,0:c
912a88b5ba8SSam Ravnborg  */
913a88b5ba8SSam Ravnborg static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
914a88b5ba8SSam Ravnborg {
915a88b5ba8SSam Ravnborg 	struct linux_prom64_registers *regs;
916a88b5ba8SSam Ravnborg 	struct property *rprop;
917a88b5ba8SSam Ravnborg 	u32 high_bits, low_bits, type;
918a88b5ba8SSam Ravnborg 
919a88b5ba8SSam Ravnborg 	rprop = of_find_property(dp, "reg", NULL);
920a88b5ba8SSam Ravnborg 	if (!rprop)
921a88b5ba8SSam Ravnborg 		return;
922a88b5ba8SSam Ravnborg 
923a88b5ba8SSam Ravnborg 	regs = rprop->value;
924a88b5ba8SSam Ravnborg 	if (!is_root_node(dp->parent)) {
925a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x,%x",
926a88b5ba8SSam Ravnborg 			dp->name,
927a88b5ba8SSam Ravnborg 			(unsigned int) (regs->phys_addr >> 32UL),
928a88b5ba8SSam Ravnborg 			(unsigned int) (regs->phys_addr & 0xffffffffUL));
929a88b5ba8SSam Ravnborg 		return;
930a88b5ba8SSam Ravnborg 	}
931a88b5ba8SSam Ravnborg 
932a88b5ba8SSam Ravnborg 	type = regs->phys_addr >> 60UL;
933a88b5ba8SSam Ravnborg 	high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL;
934a88b5ba8SSam Ravnborg 	low_bits = (regs->phys_addr & 0xffffffffUL);
935a88b5ba8SSam Ravnborg 
936a88b5ba8SSam Ravnborg 	if (type == 0 || type == 8) {
937a88b5ba8SSam Ravnborg 		const char *prefix = (type == 0) ? "m" : "i";
938a88b5ba8SSam Ravnborg 
939a88b5ba8SSam Ravnborg 		if (low_bits)
940a88b5ba8SSam Ravnborg 			sprintf(tmp_buf, "%s@%s%x,%x",
941a88b5ba8SSam Ravnborg 				dp->name, prefix,
942a88b5ba8SSam Ravnborg 				high_bits, low_bits);
943a88b5ba8SSam Ravnborg 		else
944a88b5ba8SSam Ravnborg 			sprintf(tmp_buf, "%s@%s%x",
945a88b5ba8SSam Ravnborg 				dp->name,
946a88b5ba8SSam Ravnborg 				prefix,
947a88b5ba8SSam Ravnborg 				high_bits);
948a88b5ba8SSam Ravnborg 	} else if (type == 12) {
949a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x",
950a88b5ba8SSam Ravnborg 			dp->name, high_bits);
951a88b5ba8SSam Ravnborg 	}
952a88b5ba8SSam Ravnborg }
953a88b5ba8SSam Ravnborg 
954a88b5ba8SSam Ravnborg static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
955a88b5ba8SSam Ravnborg {
956a88b5ba8SSam Ravnborg 	struct linux_prom64_registers *regs;
957a88b5ba8SSam Ravnborg 	struct property *prop;
958a88b5ba8SSam Ravnborg 
959a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
960a88b5ba8SSam Ravnborg 	if (!prop)
961a88b5ba8SSam Ravnborg 		return;
962a88b5ba8SSam Ravnborg 
963a88b5ba8SSam Ravnborg 	regs = prop->value;
964a88b5ba8SSam Ravnborg 	if (!is_root_node(dp->parent)) {
965a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x,%x",
966a88b5ba8SSam Ravnborg 			dp->name,
967a88b5ba8SSam Ravnborg 			(unsigned int) (regs->phys_addr >> 32UL),
968a88b5ba8SSam Ravnborg 			(unsigned int) (regs->phys_addr & 0xffffffffUL));
969a88b5ba8SSam Ravnborg 		return;
970a88b5ba8SSam Ravnborg 	}
971a88b5ba8SSam Ravnborg 
972a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "upa-portid", NULL);
973a88b5ba8SSam Ravnborg 	if (!prop)
974a88b5ba8SSam Ravnborg 		prop = of_find_property(dp, "portid", NULL);
975a88b5ba8SSam Ravnborg 	if (prop) {
976a88b5ba8SSam Ravnborg 		unsigned long mask = 0xffffffffUL;
977a88b5ba8SSam Ravnborg 
978a88b5ba8SSam Ravnborg 		if (tlb_type >= cheetah)
979a88b5ba8SSam Ravnborg 			mask = 0x7fffff;
980a88b5ba8SSam Ravnborg 
981a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x,%x",
982a88b5ba8SSam Ravnborg 			dp->name,
983a88b5ba8SSam Ravnborg 			*(u32 *)prop->value,
984a88b5ba8SSam Ravnborg 			(unsigned int) (regs->phys_addr & mask));
985a88b5ba8SSam Ravnborg 	}
986a88b5ba8SSam Ravnborg }
987a88b5ba8SSam Ravnborg 
988a88b5ba8SSam Ravnborg /* "name@slot,offset"  */
989a88b5ba8SSam Ravnborg static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
990a88b5ba8SSam Ravnborg {
991a88b5ba8SSam Ravnborg 	struct linux_prom_registers *regs;
992a88b5ba8SSam Ravnborg 	struct property *prop;
993a88b5ba8SSam Ravnborg 
994a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
995a88b5ba8SSam Ravnborg 	if (!prop)
996a88b5ba8SSam Ravnborg 		return;
997a88b5ba8SSam Ravnborg 
998a88b5ba8SSam Ravnborg 	regs = prop->value;
999a88b5ba8SSam Ravnborg 	sprintf(tmp_buf, "%s@%x,%x",
1000a88b5ba8SSam Ravnborg 		dp->name,
1001a88b5ba8SSam Ravnborg 		regs->which_io,
1002a88b5ba8SSam Ravnborg 		regs->phys_addr);
1003a88b5ba8SSam Ravnborg }
1004a88b5ba8SSam Ravnborg 
1005a88b5ba8SSam Ravnborg /* "name@devnum[,func]" */
1006a88b5ba8SSam Ravnborg static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
1007a88b5ba8SSam Ravnborg {
1008a88b5ba8SSam Ravnborg 	struct linux_prom_pci_registers *regs;
1009a88b5ba8SSam Ravnborg 	struct property *prop;
1010a88b5ba8SSam Ravnborg 	unsigned int devfn;
1011a88b5ba8SSam Ravnborg 
1012a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1013a88b5ba8SSam Ravnborg 	if (!prop)
1014a88b5ba8SSam Ravnborg 		return;
1015a88b5ba8SSam Ravnborg 
1016a88b5ba8SSam Ravnborg 	regs = prop->value;
1017a88b5ba8SSam Ravnborg 	devfn = (regs->phys_hi >> 8) & 0xff;
1018a88b5ba8SSam Ravnborg 	if (devfn & 0x07) {
1019a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x,%x",
1020a88b5ba8SSam Ravnborg 			dp->name,
1021a88b5ba8SSam Ravnborg 			devfn >> 3,
1022a88b5ba8SSam Ravnborg 			devfn & 0x07);
1023a88b5ba8SSam Ravnborg 	} else {
1024a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x",
1025a88b5ba8SSam Ravnborg 			dp->name,
1026a88b5ba8SSam Ravnborg 			devfn >> 3);
1027a88b5ba8SSam Ravnborg 	}
1028a88b5ba8SSam Ravnborg }
1029a88b5ba8SSam Ravnborg 
1030a88b5ba8SSam Ravnborg /* "name@UPA_PORTID,offset" */
1031a88b5ba8SSam Ravnborg static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
1032a88b5ba8SSam Ravnborg {
1033a88b5ba8SSam Ravnborg 	struct linux_prom64_registers *regs;
1034a88b5ba8SSam Ravnborg 	struct property *prop;
1035a88b5ba8SSam Ravnborg 
1036a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1037a88b5ba8SSam Ravnborg 	if (!prop)
1038a88b5ba8SSam Ravnborg 		return;
1039a88b5ba8SSam Ravnborg 
1040a88b5ba8SSam Ravnborg 	regs = prop->value;
1041a88b5ba8SSam Ravnborg 
1042a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "upa-portid", NULL);
1043a88b5ba8SSam Ravnborg 	if (!prop)
1044a88b5ba8SSam Ravnborg 		return;
1045a88b5ba8SSam Ravnborg 
1046a88b5ba8SSam Ravnborg 	sprintf(tmp_buf, "%s@%x,%x",
1047a88b5ba8SSam Ravnborg 		dp->name,
1048a88b5ba8SSam Ravnborg 		*(u32 *) prop->value,
1049a88b5ba8SSam Ravnborg 		(unsigned int) (regs->phys_addr & 0xffffffffUL));
1050a88b5ba8SSam Ravnborg }
1051a88b5ba8SSam Ravnborg 
1052a88b5ba8SSam Ravnborg /* "name@reg" */
1053a88b5ba8SSam Ravnborg static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
1054a88b5ba8SSam Ravnborg {
1055a88b5ba8SSam Ravnborg 	struct property *prop;
1056a88b5ba8SSam Ravnborg 	u32 *regs;
1057a88b5ba8SSam Ravnborg 
1058a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1059a88b5ba8SSam Ravnborg 	if (!prop)
1060a88b5ba8SSam Ravnborg 		return;
1061a88b5ba8SSam Ravnborg 
1062a88b5ba8SSam Ravnborg 	regs = prop->value;
1063a88b5ba8SSam Ravnborg 
1064a88b5ba8SSam Ravnborg 	sprintf(tmp_buf, "%s@%x", dp->name, *regs);
1065a88b5ba8SSam Ravnborg }
1066a88b5ba8SSam Ravnborg 
1067a88b5ba8SSam Ravnborg /* "name@addrhi,addrlo" */
1068a88b5ba8SSam Ravnborg static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
1069a88b5ba8SSam Ravnborg {
1070a88b5ba8SSam Ravnborg 	struct linux_prom64_registers *regs;
1071a88b5ba8SSam Ravnborg 	struct property *prop;
1072a88b5ba8SSam Ravnborg 
1073a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1074a88b5ba8SSam Ravnborg 	if (!prop)
1075a88b5ba8SSam Ravnborg 		return;
1076a88b5ba8SSam Ravnborg 
1077a88b5ba8SSam Ravnborg 	regs = prop->value;
1078a88b5ba8SSam Ravnborg 
1079a88b5ba8SSam Ravnborg 	sprintf(tmp_buf, "%s@%x,%x",
1080a88b5ba8SSam Ravnborg 		dp->name,
1081a88b5ba8SSam Ravnborg 		(unsigned int) (regs->phys_addr >> 32UL),
1082a88b5ba8SSam Ravnborg 		(unsigned int) (regs->phys_addr & 0xffffffffUL));
1083a88b5ba8SSam Ravnborg }
1084a88b5ba8SSam Ravnborg 
1085a88b5ba8SSam Ravnborg /* "name@bus,addr" */
1086a88b5ba8SSam Ravnborg static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
1087a88b5ba8SSam Ravnborg {
1088a88b5ba8SSam Ravnborg 	struct property *prop;
1089a88b5ba8SSam Ravnborg 	u32 *regs;
1090a88b5ba8SSam Ravnborg 
1091a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1092a88b5ba8SSam Ravnborg 	if (!prop)
1093a88b5ba8SSam Ravnborg 		return;
1094a88b5ba8SSam Ravnborg 
1095a88b5ba8SSam Ravnborg 	regs = prop->value;
1096a88b5ba8SSam Ravnborg 
1097a88b5ba8SSam Ravnborg 	/* This actually isn't right... should look at the #address-cells
1098a88b5ba8SSam Ravnborg 	 * property of the i2c bus node etc. etc.
1099a88b5ba8SSam Ravnborg 	 */
1100a88b5ba8SSam Ravnborg 	sprintf(tmp_buf, "%s@%x,%x",
1101a88b5ba8SSam Ravnborg 		dp->name, regs[0], regs[1]);
1102a88b5ba8SSam Ravnborg }
1103a88b5ba8SSam Ravnborg 
1104a88b5ba8SSam Ravnborg /* "name@reg0[,reg1]" */
1105a88b5ba8SSam Ravnborg static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
1106a88b5ba8SSam Ravnborg {
1107a88b5ba8SSam Ravnborg 	struct property *prop;
1108a88b5ba8SSam Ravnborg 	u32 *regs;
1109a88b5ba8SSam Ravnborg 
1110a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1111a88b5ba8SSam Ravnborg 	if (!prop)
1112a88b5ba8SSam Ravnborg 		return;
1113a88b5ba8SSam Ravnborg 
1114a88b5ba8SSam Ravnborg 	regs = prop->value;
1115a88b5ba8SSam Ravnborg 
1116a88b5ba8SSam Ravnborg 	if (prop->length == sizeof(u32) || regs[1] == 1) {
1117a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x",
1118a88b5ba8SSam Ravnborg 			dp->name, regs[0]);
1119a88b5ba8SSam Ravnborg 	} else {
1120a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%x,%x",
1121a88b5ba8SSam Ravnborg 			dp->name, regs[0], regs[1]);
1122a88b5ba8SSam Ravnborg 	}
1123a88b5ba8SSam Ravnborg }
1124a88b5ba8SSam Ravnborg 
1125a88b5ba8SSam Ravnborg /* "name@reg0reg1[,reg2reg3]" */
1126a88b5ba8SSam Ravnborg static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
1127a88b5ba8SSam Ravnborg {
1128a88b5ba8SSam Ravnborg 	struct property *prop;
1129a88b5ba8SSam Ravnborg 	u32 *regs;
1130a88b5ba8SSam Ravnborg 
1131a88b5ba8SSam Ravnborg 	prop = of_find_property(dp, "reg", NULL);
1132a88b5ba8SSam Ravnborg 	if (!prop)
1133a88b5ba8SSam Ravnborg 		return;
1134a88b5ba8SSam Ravnborg 
1135a88b5ba8SSam Ravnborg 	regs = prop->value;
1136a88b5ba8SSam Ravnborg 
1137a88b5ba8SSam Ravnborg 	if (regs[2] || regs[3]) {
1138a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
1139a88b5ba8SSam Ravnborg 			dp->name, regs[0], regs[1], regs[2], regs[3]);
1140a88b5ba8SSam Ravnborg 	} else {
1141a88b5ba8SSam Ravnborg 		sprintf(tmp_buf, "%s@%08x%08x",
1142a88b5ba8SSam Ravnborg 			dp->name, regs[0], regs[1]);
1143a88b5ba8SSam Ravnborg 	}
1144a88b5ba8SSam Ravnborg }
1145a88b5ba8SSam Ravnborg 
1146a88b5ba8SSam Ravnborg static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
1147a88b5ba8SSam Ravnborg {
1148a88b5ba8SSam Ravnborg 	struct device_node *parent = dp->parent;
1149a88b5ba8SSam Ravnborg 
1150a88b5ba8SSam Ravnborg 	if (parent != NULL) {
1151a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "pci") ||
1152a88b5ba8SSam Ravnborg 		    !strcmp(parent->type, "pciex")) {
1153a88b5ba8SSam Ravnborg 			pci_path_component(dp, tmp_buf);
1154a88b5ba8SSam Ravnborg 			return;
1155a88b5ba8SSam Ravnborg 		}
1156a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "sbus")) {
1157a88b5ba8SSam Ravnborg 			sbus_path_component(dp, tmp_buf);
1158a88b5ba8SSam Ravnborg 			return;
1159a88b5ba8SSam Ravnborg 		}
1160a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "upa")) {
1161a88b5ba8SSam Ravnborg 			upa_path_component(dp, tmp_buf);
1162a88b5ba8SSam Ravnborg 			return;
1163a88b5ba8SSam Ravnborg 		}
1164a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "ebus")) {
1165a88b5ba8SSam Ravnborg 			ebus_path_component(dp, tmp_buf);
1166a88b5ba8SSam Ravnborg 			return;
1167a88b5ba8SSam Ravnborg 		}
1168a88b5ba8SSam Ravnborg 		if (!strcmp(parent->name, "usb") ||
1169a88b5ba8SSam Ravnborg 		    !strcmp(parent->name, "hub")) {
1170a88b5ba8SSam Ravnborg 			usb_path_component(dp, tmp_buf);
1171a88b5ba8SSam Ravnborg 			return;
1172a88b5ba8SSam Ravnborg 		}
1173a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "i2c")) {
1174a88b5ba8SSam Ravnborg 			i2c_path_component(dp, tmp_buf);
1175a88b5ba8SSam Ravnborg 			return;
1176a88b5ba8SSam Ravnborg 		}
1177a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "firewire")) {
1178a88b5ba8SSam Ravnborg 			ieee1394_path_component(dp, tmp_buf);
1179a88b5ba8SSam Ravnborg 			return;
1180a88b5ba8SSam Ravnborg 		}
1181a88b5ba8SSam Ravnborg 		if (!strcmp(parent->type, "virtual-devices")) {
1182a88b5ba8SSam Ravnborg 			vdev_path_component(dp, tmp_buf);
1183a88b5ba8SSam Ravnborg 			return;
1184a88b5ba8SSam Ravnborg 		}
1185a88b5ba8SSam Ravnborg 		/* "isa" is handled with platform naming */
1186a88b5ba8SSam Ravnborg 	}
1187a88b5ba8SSam Ravnborg 
1188a88b5ba8SSam Ravnborg 	/* Use platform naming convention.  */
1189a88b5ba8SSam Ravnborg 	if (tlb_type == hypervisor) {
1190a88b5ba8SSam Ravnborg 		sun4v_path_component(dp, tmp_buf);
1191a88b5ba8SSam Ravnborg 		return;
1192a88b5ba8SSam Ravnborg 	} else {
1193a88b5ba8SSam Ravnborg 		sun4u_path_component(dp, tmp_buf);
1194a88b5ba8SSam Ravnborg 	}
1195a88b5ba8SSam Ravnborg }
1196a88b5ba8SSam Ravnborg 
1197a88b5ba8SSam Ravnborg static char * __init build_path_component(struct device_node *dp)
1198a88b5ba8SSam Ravnborg {
1199a88b5ba8SSam Ravnborg 	char tmp_buf[64], *n;
1200a88b5ba8SSam Ravnborg 
1201a88b5ba8SSam Ravnborg 	tmp_buf[0] = '\0';
1202a88b5ba8SSam Ravnborg 	__build_path_component(dp, tmp_buf);
1203a88b5ba8SSam Ravnborg 	if (tmp_buf[0] == '\0')
1204a88b5ba8SSam Ravnborg 		strcpy(tmp_buf, dp->name);
1205a88b5ba8SSam Ravnborg 
1206a88b5ba8SSam Ravnborg 	n = prom_early_alloc(strlen(tmp_buf) + 1);
1207a88b5ba8SSam Ravnborg 	strcpy(n, tmp_buf);
1208a88b5ba8SSam Ravnborg 
1209a88b5ba8SSam Ravnborg 	return n;
1210a88b5ba8SSam Ravnborg }
1211a88b5ba8SSam Ravnborg 
1212a88b5ba8SSam Ravnborg static char * __init build_full_name(struct device_node *dp)
1213a88b5ba8SSam Ravnborg {
1214a88b5ba8SSam Ravnborg 	int len, ourlen, plen;
1215a88b5ba8SSam Ravnborg 	char *n;
1216a88b5ba8SSam Ravnborg 
1217a88b5ba8SSam Ravnborg 	plen = strlen(dp->parent->full_name);
1218a88b5ba8SSam Ravnborg 	ourlen = strlen(dp->path_component_name);
1219a88b5ba8SSam Ravnborg 	len = ourlen + plen + 2;
1220a88b5ba8SSam Ravnborg 
1221a88b5ba8SSam Ravnborg 	n = prom_early_alloc(len);
1222a88b5ba8SSam Ravnborg 	strcpy(n, dp->parent->full_name);
1223a88b5ba8SSam Ravnborg 	if (!is_root_node(dp->parent)) {
1224a88b5ba8SSam Ravnborg 		strcpy(n + plen, "/");
1225a88b5ba8SSam Ravnborg 		plen++;
1226a88b5ba8SSam Ravnborg 	}
1227a88b5ba8SSam Ravnborg 	strcpy(n + plen, dp->path_component_name);
1228a88b5ba8SSam Ravnborg 
1229a88b5ba8SSam Ravnborg 	return n;
1230a88b5ba8SSam Ravnborg }
1231a88b5ba8SSam Ravnborg 
1232a88b5ba8SSam Ravnborg static unsigned int unique_id;
1233a88b5ba8SSam Ravnborg 
1234a88b5ba8SSam Ravnborg static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
1235a88b5ba8SSam Ravnborg {
1236a88b5ba8SSam Ravnborg 	static struct property *tmp = NULL;
1237a88b5ba8SSam Ravnborg 	struct property *p;
1238a88b5ba8SSam Ravnborg 
1239a88b5ba8SSam Ravnborg 	if (tmp) {
1240a88b5ba8SSam Ravnborg 		p = tmp;
1241a88b5ba8SSam Ravnborg 		memset(p, 0, sizeof(*p) + 32);
1242a88b5ba8SSam Ravnborg 		tmp = NULL;
1243a88b5ba8SSam Ravnborg 	} else {
1244a88b5ba8SSam Ravnborg 		p = prom_early_alloc(sizeof(struct property) + 32);
1245a88b5ba8SSam Ravnborg 		p->unique_id = unique_id++;
1246a88b5ba8SSam Ravnborg 	}
1247a88b5ba8SSam Ravnborg 
1248a88b5ba8SSam Ravnborg 	p->name = (char *) (p + 1);
1249a88b5ba8SSam Ravnborg 	if (special_name) {
1250a88b5ba8SSam Ravnborg 		strcpy(p->name, special_name);
1251a88b5ba8SSam Ravnborg 		p->length = special_len;
1252a88b5ba8SSam Ravnborg 		p->value = prom_early_alloc(special_len);
1253a88b5ba8SSam Ravnborg 		memcpy(p->value, special_val, special_len);
1254a88b5ba8SSam Ravnborg 	} else {
1255a88b5ba8SSam Ravnborg 		if (prev == NULL) {
1256a88b5ba8SSam Ravnborg 			prom_firstprop(node, p->name);
1257a88b5ba8SSam Ravnborg 		} else {
1258a88b5ba8SSam Ravnborg 			prom_nextprop(node, prev, p->name);
1259a88b5ba8SSam Ravnborg 		}
1260a88b5ba8SSam Ravnborg 		if (strlen(p->name) == 0) {
1261a88b5ba8SSam Ravnborg 			tmp = p;
1262a88b5ba8SSam Ravnborg 			return NULL;
1263a88b5ba8SSam Ravnborg 		}
1264a88b5ba8SSam Ravnborg 		p->length = prom_getproplen(node, p->name);
1265a88b5ba8SSam Ravnborg 		if (p->length <= 0) {
1266a88b5ba8SSam Ravnborg 			p->length = 0;
1267a88b5ba8SSam Ravnborg 		} else {
1268a88b5ba8SSam Ravnborg 			p->value = prom_early_alloc(p->length + 1);
1269a88b5ba8SSam Ravnborg 			prom_getproperty(node, p->name, p->value, p->length);
1270a88b5ba8SSam Ravnborg 			((unsigned char *)p->value)[p->length] = '\0';
1271a88b5ba8SSam Ravnborg 		}
1272a88b5ba8SSam Ravnborg 	}
1273a88b5ba8SSam Ravnborg 	return p;
1274a88b5ba8SSam Ravnborg }
1275a88b5ba8SSam Ravnborg 
1276a88b5ba8SSam Ravnborg static struct property * __init build_prop_list(phandle node)
1277a88b5ba8SSam Ravnborg {
1278a88b5ba8SSam Ravnborg 	struct property *head, *tail;
1279a88b5ba8SSam Ravnborg 
1280a88b5ba8SSam Ravnborg 	head = tail = build_one_prop(node, NULL,
1281a88b5ba8SSam Ravnborg 				     ".node", &node, sizeof(node));
1282a88b5ba8SSam Ravnborg 
1283a88b5ba8SSam Ravnborg 	tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
1284a88b5ba8SSam Ravnborg 	tail = tail->next;
1285a88b5ba8SSam Ravnborg 	while(tail) {
1286a88b5ba8SSam Ravnborg 		tail->next = build_one_prop(node, tail->name,
1287a88b5ba8SSam Ravnborg 					    NULL, NULL, 0);
1288a88b5ba8SSam Ravnborg 		tail = tail->next;
1289a88b5ba8SSam Ravnborg 	}
1290a88b5ba8SSam Ravnborg 
1291a88b5ba8SSam Ravnborg 	return head;
1292a88b5ba8SSam Ravnborg }
1293a88b5ba8SSam Ravnborg 
1294a88b5ba8SSam Ravnborg static char * __init get_one_property(phandle node, const char *name)
1295a88b5ba8SSam Ravnborg {
1296a88b5ba8SSam Ravnborg 	char *buf = "<NULL>";
1297a88b5ba8SSam Ravnborg 	int len;
1298a88b5ba8SSam Ravnborg 
1299a88b5ba8SSam Ravnborg 	len = prom_getproplen(node, name);
1300a88b5ba8SSam Ravnborg 	if (len > 0) {
1301a88b5ba8SSam Ravnborg 		buf = prom_early_alloc(len);
1302a88b5ba8SSam Ravnborg 		prom_getproperty(node, name, buf, len);
1303a88b5ba8SSam Ravnborg 	}
1304a88b5ba8SSam Ravnborg 
1305a88b5ba8SSam Ravnborg 	return buf;
1306a88b5ba8SSam Ravnborg }
1307a88b5ba8SSam Ravnborg 
1308a88b5ba8SSam Ravnborg static struct device_node * __init create_node(phandle node, struct device_node *parent)
1309a88b5ba8SSam Ravnborg {
1310a88b5ba8SSam Ravnborg 	struct device_node *dp;
1311a88b5ba8SSam Ravnborg 
1312a88b5ba8SSam Ravnborg 	if (!node)
1313a88b5ba8SSam Ravnborg 		return NULL;
1314a88b5ba8SSam Ravnborg 
1315a88b5ba8SSam Ravnborg 	dp = prom_early_alloc(sizeof(*dp));
1316a88b5ba8SSam Ravnborg 	dp->unique_id = unique_id++;
1317a88b5ba8SSam Ravnborg 	dp->parent = parent;
1318a88b5ba8SSam Ravnborg 
1319a88b5ba8SSam Ravnborg 	kref_init(&dp->kref);
1320a88b5ba8SSam Ravnborg 
1321a88b5ba8SSam Ravnborg 	dp->name = get_one_property(node, "name");
1322a88b5ba8SSam Ravnborg 	dp->type = get_one_property(node, "device_type");
1323a88b5ba8SSam Ravnborg 	dp->node = node;
1324a88b5ba8SSam Ravnborg 
1325a88b5ba8SSam Ravnborg 	dp->properties = build_prop_list(node);
1326a88b5ba8SSam Ravnborg 
1327a88b5ba8SSam Ravnborg 	irq_trans_init(dp);
1328a88b5ba8SSam Ravnborg 
1329a88b5ba8SSam Ravnborg 	return dp;
1330a88b5ba8SSam Ravnborg }
1331a88b5ba8SSam Ravnborg 
1332a88b5ba8SSam Ravnborg static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
1333a88b5ba8SSam Ravnborg {
1334a88b5ba8SSam Ravnborg 	struct device_node *ret = NULL, *prev_sibling = NULL;
1335a88b5ba8SSam Ravnborg 	struct device_node *dp;
1336a88b5ba8SSam Ravnborg 
1337a88b5ba8SSam Ravnborg 	while (1) {
1338a88b5ba8SSam Ravnborg 		dp = create_node(node, parent);
1339a88b5ba8SSam Ravnborg 		if (!dp)
1340a88b5ba8SSam Ravnborg 			break;
1341a88b5ba8SSam Ravnborg 
1342a88b5ba8SSam Ravnborg 		if (prev_sibling)
1343a88b5ba8SSam Ravnborg 			prev_sibling->sibling = dp;
1344a88b5ba8SSam Ravnborg 
1345a88b5ba8SSam Ravnborg 		if (!ret)
1346a88b5ba8SSam Ravnborg 			ret = dp;
1347a88b5ba8SSam Ravnborg 		prev_sibling = dp;
1348a88b5ba8SSam Ravnborg 
1349a88b5ba8SSam Ravnborg 		*(*nextp) = dp;
1350a88b5ba8SSam Ravnborg 		*nextp = &dp->allnext;
1351a88b5ba8SSam Ravnborg 
1352a88b5ba8SSam Ravnborg 		dp->path_component_name = build_path_component(dp);
1353a88b5ba8SSam Ravnborg 		dp->full_name = build_full_name(dp);
1354a88b5ba8SSam Ravnborg 
1355a88b5ba8SSam Ravnborg 		dp->child = build_tree(dp, prom_getchild(node), nextp);
1356a88b5ba8SSam Ravnborg 
1357a88b5ba8SSam Ravnborg 		node = prom_getsibling(node);
1358a88b5ba8SSam Ravnborg 	}
1359a88b5ba8SSam Ravnborg 
1360a88b5ba8SSam Ravnborg 	return ret;
1361a88b5ba8SSam Ravnborg }
1362a88b5ba8SSam Ravnborg 
1363a88b5ba8SSam Ravnborg static const char *get_mid_prop(void)
1364a88b5ba8SSam Ravnborg {
1365a88b5ba8SSam Ravnborg 	return (tlb_type == spitfire ? "upa-portid" : "portid");
1366a88b5ba8SSam Ravnborg }
1367a88b5ba8SSam Ravnborg 
1368a88b5ba8SSam Ravnborg struct device_node *of_find_node_by_cpuid(int cpuid)
1369a88b5ba8SSam Ravnborg {
1370a88b5ba8SSam Ravnborg 	struct device_node *dp;
1371a88b5ba8SSam Ravnborg 	const char *mid_prop = get_mid_prop();
1372a88b5ba8SSam Ravnborg 
1373a88b5ba8SSam Ravnborg 	for_each_node_by_type(dp, "cpu") {
1374a88b5ba8SSam Ravnborg 		int id = of_getintprop_default(dp, mid_prop, -1);
1375a88b5ba8SSam Ravnborg 		const char *this_mid_prop = mid_prop;
1376a88b5ba8SSam Ravnborg 
1377a88b5ba8SSam Ravnborg 		if (id < 0) {
1378a88b5ba8SSam Ravnborg 			this_mid_prop = "cpuid";
1379a88b5ba8SSam Ravnborg 			id = of_getintprop_default(dp, this_mid_prop, -1);
1380a88b5ba8SSam Ravnborg 		}
1381a88b5ba8SSam Ravnborg 
1382a88b5ba8SSam Ravnborg 		if (id < 0) {
1383a88b5ba8SSam Ravnborg 			prom_printf("OF: Serious problem, cpu lacks "
1384a88b5ba8SSam Ravnborg 				    "%s property", this_mid_prop);
1385a88b5ba8SSam Ravnborg 			prom_halt();
1386a88b5ba8SSam Ravnborg 		}
1387a88b5ba8SSam Ravnborg 		if (cpuid == id)
1388a88b5ba8SSam Ravnborg 			return dp;
1389a88b5ba8SSam Ravnborg 	}
1390a88b5ba8SSam Ravnborg 	return NULL;
1391a88b5ba8SSam Ravnborg }
1392a88b5ba8SSam Ravnborg 
1393a88b5ba8SSam Ravnborg static void __init of_fill_in_cpu_data(void)
1394a88b5ba8SSam Ravnborg {
1395a88b5ba8SSam Ravnborg 	struct device_node *dp;
1396a88b5ba8SSam Ravnborg 	const char *mid_prop = get_mid_prop();
1397a88b5ba8SSam Ravnborg 
1398a88b5ba8SSam Ravnborg 	ncpus_probed = 0;
1399a88b5ba8SSam Ravnborg 	for_each_node_by_type(dp, "cpu") {
1400a88b5ba8SSam Ravnborg 		int cpuid = of_getintprop_default(dp, mid_prop, -1);
1401a88b5ba8SSam Ravnborg 		const char *this_mid_prop = mid_prop;
1402a88b5ba8SSam Ravnborg 		struct device_node *portid_parent;
1403a88b5ba8SSam Ravnborg 		int portid = -1;
1404a88b5ba8SSam Ravnborg 
1405a88b5ba8SSam Ravnborg 		portid_parent = NULL;
1406a88b5ba8SSam Ravnborg 		if (cpuid < 0) {
1407a88b5ba8SSam Ravnborg 			this_mid_prop = "cpuid";
1408a88b5ba8SSam Ravnborg 			cpuid = of_getintprop_default(dp, this_mid_prop, -1);
1409a88b5ba8SSam Ravnborg 			if (cpuid >= 0) {
1410a88b5ba8SSam Ravnborg 				int limit = 2;
1411a88b5ba8SSam Ravnborg 
1412a88b5ba8SSam Ravnborg 				portid_parent = dp;
1413a88b5ba8SSam Ravnborg 				while (limit--) {
1414a88b5ba8SSam Ravnborg 					portid_parent = portid_parent->parent;
1415a88b5ba8SSam Ravnborg 					if (!portid_parent)
1416a88b5ba8SSam Ravnborg 						break;
1417a88b5ba8SSam Ravnborg 					portid = of_getintprop_default(portid_parent,
1418a88b5ba8SSam Ravnborg 								       "portid", -1);
1419a88b5ba8SSam Ravnborg 					if (portid >= 0)
1420a88b5ba8SSam Ravnborg 						break;
1421a88b5ba8SSam Ravnborg 				}
1422a88b5ba8SSam Ravnborg 			}
1423a88b5ba8SSam Ravnborg 		}
1424a88b5ba8SSam Ravnborg 
1425a88b5ba8SSam Ravnborg 		if (cpuid < 0) {
1426a88b5ba8SSam Ravnborg 			prom_printf("OF: Serious problem, cpu lacks "
1427a88b5ba8SSam Ravnborg 				    "%s property", this_mid_prop);
1428a88b5ba8SSam Ravnborg 			prom_halt();
1429a88b5ba8SSam Ravnborg 		}
1430a88b5ba8SSam Ravnborg 
1431a88b5ba8SSam Ravnborg 		ncpus_probed++;
1432a88b5ba8SSam Ravnborg 
1433a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP
1434a88b5ba8SSam Ravnborg 		if (cpuid >= NR_CPUS) {
1435a88b5ba8SSam Ravnborg 			printk(KERN_WARNING "Ignoring CPU %d which is "
1436a88b5ba8SSam Ravnborg 			       ">= NR_CPUS (%d)\n",
1437a88b5ba8SSam Ravnborg 			       cpuid, NR_CPUS);
1438a88b5ba8SSam Ravnborg 			continue;
1439a88b5ba8SSam Ravnborg 		}
1440a88b5ba8SSam Ravnborg #else
1441a88b5ba8SSam Ravnborg 		/* On uniprocessor we only want the values for the
1442a88b5ba8SSam Ravnborg 		 * real physical cpu the kernel booted onto, however
1443a88b5ba8SSam Ravnborg 		 * cpu_data() only has one entry at index 0.
1444a88b5ba8SSam Ravnborg 		 */
1445a88b5ba8SSam Ravnborg 		if (cpuid != real_hard_smp_processor_id())
1446a88b5ba8SSam Ravnborg 			continue;
1447a88b5ba8SSam Ravnborg 		cpuid = 0;
1448a88b5ba8SSam Ravnborg #endif
1449a88b5ba8SSam Ravnborg 
1450a88b5ba8SSam Ravnborg 		cpu_data(cpuid).clock_tick =
1451a88b5ba8SSam Ravnborg 			of_getintprop_default(dp, "clock-frequency", 0);
1452a88b5ba8SSam Ravnborg 
1453a88b5ba8SSam Ravnborg 		if (portid_parent) {
1454a88b5ba8SSam Ravnborg 			cpu_data(cpuid).dcache_size =
1455a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "l1-dcache-size",
1456a88b5ba8SSam Ravnborg 						      16 * 1024);
1457a88b5ba8SSam Ravnborg 			cpu_data(cpuid).dcache_line_size =
1458a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "l1-dcache-line-size",
1459a88b5ba8SSam Ravnborg 						      32);
1460a88b5ba8SSam Ravnborg 			cpu_data(cpuid).icache_size =
1461a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "l1-icache-size",
1462a88b5ba8SSam Ravnborg 						      8 * 1024);
1463a88b5ba8SSam Ravnborg 			cpu_data(cpuid).icache_line_size =
1464a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "l1-icache-line-size",
1465a88b5ba8SSam Ravnborg 						      32);
1466a88b5ba8SSam Ravnborg 			cpu_data(cpuid).ecache_size =
1467a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "l2-cache-size", 0);
1468a88b5ba8SSam Ravnborg 			cpu_data(cpuid).ecache_line_size =
1469a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "l2-cache-line-size", 0);
1470a88b5ba8SSam Ravnborg 			if (!cpu_data(cpuid).ecache_size ||
1471a88b5ba8SSam Ravnborg 			    !cpu_data(cpuid).ecache_line_size) {
1472a88b5ba8SSam Ravnborg 				cpu_data(cpuid).ecache_size =
1473a88b5ba8SSam Ravnborg 					of_getintprop_default(portid_parent,
1474a88b5ba8SSam Ravnborg 							      "l2-cache-size",
1475a88b5ba8SSam Ravnborg 							      (4 * 1024 * 1024));
1476a88b5ba8SSam Ravnborg 				cpu_data(cpuid).ecache_line_size =
1477a88b5ba8SSam Ravnborg 					of_getintprop_default(portid_parent,
1478a88b5ba8SSam Ravnborg 							      "l2-cache-line-size", 64);
1479a88b5ba8SSam Ravnborg 			}
1480a88b5ba8SSam Ravnborg 
1481a88b5ba8SSam Ravnborg 			cpu_data(cpuid).core_id = portid + 1;
1482a88b5ba8SSam Ravnborg 			cpu_data(cpuid).proc_id = portid;
1483a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP
1484a88b5ba8SSam Ravnborg 			sparc64_multi_core = 1;
1485a88b5ba8SSam Ravnborg #endif
1486a88b5ba8SSam Ravnborg 		} else {
1487a88b5ba8SSam Ravnborg 			cpu_data(cpuid).dcache_size =
1488a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "dcache-size", 16 * 1024);
1489a88b5ba8SSam Ravnborg 			cpu_data(cpuid).dcache_line_size =
1490a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "dcache-line-size", 32);
1491a88b5ba8SSam Ravnborg 
1492a88b5ba8SSam Ravnborg 			cpu_data(cpuid).icache_size =
1493a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "icache-size", 16 * 1024);
1494a88b5ba8SSam Ravnborg 			cpu_data(cpuid).icache_line_size =
1495a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "icache-line-size", 32);
1496a88b5ba8SSam Ravnborg 
1497a88b5ba8SSam Ravnborg 			cpu_data(cpuid).ecache_size =
1498a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "ecache-size",
1499a88b5ba8SSam Ravnborg 						      (4 * 1024 * 1024));
1500a88b5ba8SSam Ravnborg 			cpu_data(cpuid).ecache_line_size =
1501a88b5ba8SSam Ravnborg 				of_getintprop_default(dp, "ecache-line-size", 64);
1502a88b5ba8SSam Ravnborg 
1503a88b5ba8SSam Ravnborg 			cpu_data(cpuid).core_id = 0;
1504a88b5ba8SSam Ravnborg 			cpu_data(cpuid).proc_id = -1;
1505a88b5ba8SSam Ravnborg 		}
1506a88b5ba8SSam Ravnborg 
1507a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP
1508a88b5ba8SSam Ravnborg 		cpu_set(cpuid, cpu_present_map);
1509a88b5ba8SSam Ravnborg 		cpu_set(cpuid, cpu_possible_map);
1510a88b5ba8SSam Ravnborg #endif
1511a88b5ba8SSam Ravnborg 	}
1512a88b5ba8SSam Ravnborg 
1513a88b5ba8SSam Ravnborg 	smp_fill_in_sib_core_maps();
1514a88b5ba8SSam Ravnborg }
1515a88b5ba8SSam Ravnborg 
1516a88b5ba8SSam Ravnborg struct device_node *of_console_device;
1517a88b5ba8SSam Ravnborg EXPORT_SYMBOL(of_console_device);
1518a88b5ba8SSam Ravnborg 
1519a88b5ba8SSam Ravnborg char *of_console_path;
1520a88b5ba8SSam Ravnborg EXPORT_SYMBOL(of_console_path);
1521a88b5ba8SSam Ravnborg 
1522a88b5ba8SSam Ravnborg char *of_console_options;
1523a88b5ba8SSam Ravnborg EXPORT_SYMBOL(of_console_options);
1524a88b5ba8SSam Ravnborg 
1525a88b5ba8SSam Ravnborg static void __init of_console_init(void)
1526a88b5ba8SSam Ravnborg {
1527a88b5ba8SSam Ravnborg 	char *msg = "OF stdout device is: %s\n";
1528a88b5ba8SSam Ravnborg 	struct device_node *dp;
1529a88b5ba8SSam Ravnborg 	const char *type;
1530a88b5ba8SSam Ravnborg 	phandle node;
1531a88b5ba8SSam Ravnborg 
1532a88b5ba8SSam Ravnborg 	of_console_path = prom_early_alloc(256);
1533a88b5ba8SSam Ravnborg 	if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
1534a88b5ba8SSam Ravnborg 		prom_printf("Cannot obtain path of stdout.\n");
1535a88b5ba8SSam Ravnborg 		prom_halt();
1536a88b5ba8SSam Ravnborg 	}
1537a88b5ba8SSam Ravnborg 	of_console_options = strrchr(of_console_path, ':');
1538a88b5ba8SSam Ravnborg 	if (of_console_options) {
1539a88b5ba8SSam Ravnborg 		of_console_options++;
1540a88b5ba8SSam Ravnborg 		if (*of_console_options == '\0')
1541a88b5ba8SSam Ravnborg 			of_console_options = NULL;
1542a88b5ba8SSam Ravnborg 	}
1543a88b5ba8SSam Ravnborg 
1544a88b5ba8SSam Ravnborg 	node = prom_inst2pkg(prom_stdout);
1545a88b5ba8SSam Ravnborg 	if (!node) {
1546a88b5ba8SSam Ravnborg 		prom_printf("Cannot resolve stdout node from "
1547a88b5ba8SSam Ravnborg 			    "instance %08x.\n", prom_stdout);
1548a88b5ba8SSam Ravnborg 		prom_halt();
1549a88b5ba8SSam Ravnborg 	}
1550a88b5ba8SSam Ravnborg 
1551a88b5ba8SSam Ravnborg 	dp = of_find_node_by_phandle(node);
1552a88b5ba8SSam Ravnborg 	type = of_get_property(dp, "device_type", NULL);
1553a88b5ba8SSam Ravnborg 	if (!type) {
1554a88b5ba8SSam Ravnborg 		prom_printf("Console stdout lacks device_type property.\n");
1555a88b5ba8SSam Ravnborg 		prom_halt();
1556a88b5ba8SSam Ravnborg 	}
1557a88b5ba8SSam Ravnborg 
1558a88b5ba8SSam Ravnborg 	if (strcmp(type, "display") && strcmp(type, "serial")) {
1559a88b5ba8SSam Ravnborg 		prom_printf("Console device_type is neither display "
1560a88b5ba8SSam Ravnborg 			    "nor serial.\n");
1561a88b5ba8SSam Ravnborg 		prom_halt();
1562a88b5ba8SSam Ravnborg 	}
1563a88b5ba8SSam Ravnborg 
1564a88b5ba8SSam Ravnborg 	of_console_device = dp;
1565a88b5ba8SSam Ravnborg 
1566a88b5ba8SSam Ravnborg 	printk(msg, of_console_path);
1567a88b5ba8SSam Ravnborg }
1568a88b5ba8SSam Ravnborg 
1569a88b5ba8SSam Ravnborg void __init prom_build_devicetree(void)
1570a88b5ba8SSam Ravnborg {
1571a88b5ba8SSam Ravnborg 	struct device_node **nextp;
1572a88b5ba8SSam Ravnborg 
1573a88b5ba8SSam Ravnborg 	allnodes = create_node(prom_root_node, NULL);
1574a88b5ba8SSam Ravnborg 	allnodes->path_component_name = "";
1575a88b5ba8SSam Ravnborg 	allnodes->full_name = "/";
1576a88b5ba8SSam Ravnborg 
1577a88b5ba8SSam Ravnborg 	nextp = &allnodes->allnext;
1578a88b5ba8SSam Ravnborg 	allnodes->child = build_tree(allnodes,
1579a88b5ba8SSam Ravnborg 				     prom_getchild(allnodes->node),
1580a88b5ba8SSam Ravnborg 				     &nextp);
1581a88b5ba8SSam Ravnborg 	of_console_init();
1582a88b5ba8SSam Ravnborg 
1583a88b5ba8SSam Ravnborg 	printk("PROM: Built device tree with %u bytes of memory.\n",
1584a88b5ba8SSam Ravnborg 	       prom_early_allocated);
1585a88b5ba8SSam Ravnborg 
1586a88b5ba8SSam Ravnborg 	if (tlb_type != hypervisor)
1587a88b5ba8SSam Ravnborg 		of_fill_in_cpu_data();
1588a88b5ba8SSam Ravnborg }
1589