1139825Simp/*-
277957Sbenno * Copyright (C) 1996 Wolfgang Solfrank.
377957Sbenno * Copyright (C) 1996 TooLs GmbH.
477957Sbenno * All rights reserved.
577957Sbenno *
677957Sbenno * Redistribution and use in source and binary forms, with or without
777957Sbenno * modification, are permitted provided that the following conditions
877957Sbenno * are met:
977957Sbenno * 1. Redistributions of source code must retain the above copyright
1077957Sbenno *    notice, this list of conditions and the following disclaimer.
1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1277957Sbenno *    notice, this list of conditions and the following disclaimer in the
1377957Sbenno *    documentation and/or other materials provided with the distribution.
1477957Sbenno * 3. All advertising materials mentioning features or use of this software
1577957Sbenno *    must display the following acknowledgement:
1677957Sbenno *	This product includes software developed by TooLs GmbH.
1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products
1877957Sbenno *    derived from this software without specific prior written permission.
1977957Sbenno *
2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3077957Sbenno *
3177957Sbenno * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
3277957Sbenno */
3377957Sbenno
34113038Sobrien#include <sys/cdefs.h>
35113038Sobrien__FBSDID("$FreeBSD$");
3677957Sbenno
3777957Sbenno#include <sys/param.h>
3877957Sbenno#include <sys/bus.h>
3977957Sbenno#include <sys/systm.h>
4077957Sbenno#include <sys/conf.h>
4177957Sbenno#include <sys/disk.h>
4277957Sbenno#include <sys/fcntl.h>
4377957Sbenno#include <sys/malloc.h>
44208364Snwhitehorn#include <sys/smp.h>
4577957Sbenno#include <sys/stat.h>
4677957Sbenno
4799665Sbenno#include <net/ethernet.h>
4899665Sbenno
4977957Sbenno#include <dev/ofw/openfirm.h>
50165151Smarcel#include <dev/ofw/ofw_pci.h>
51183882Snwhitehorn#include <dev/ofw/ofw_bus.h>
5277957Sbenno
5390643Sbenno#include <vm/vm.h>
5490643Sbenno#include <vm/vm_param.h>
5590643Sbenno#include <vm/vm_page.h>
5690643Sbenno
57160714Smarcel#include <machine/bus.h>
58199886Snwhitehorn#include <machine/cpu.h>
59160714Smarcel#include <machine/md_var.h>
60192067Snwhitehorn#include <machine/platform.h>
6199030Sbenno#include <machine/ofw_machdep.h>
62259235Sandreast#include <machine/trap.h>
6377957Sbenno
64259235Sandreast#ifdef AIM
65151891Sgrehanextern register_t ofmsr[5];
66222613Snwhitehornextern void	*openfirmware_entry;
67186347Snwhitehornstatic void	*fdt;
68186347Snwhitehornint		ofw_real_mode;
69259235Sandreastextern char     save_trap_init[0x2f00];          /* EXC_LAST */
70259235Sandreastchar            save_trap_of[0x2f00];            /* EXC_LAST */
7177957Sbenno
72222667Snwhitehornint		ofwcall(void *);
73186347Snwhitehornstatic int	openfirmware(void *args);
74186347Snwhitehorn
75259235Sandreast__inline void
76259235Sandreastofw_save_trap_vec(char *save_trap_vec)
77259235Sandreast{
78266020Sian	if (!ofw_real_mode)
79259235Sandreast                return;
80259235Sandreast
81259235Sandreast	bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
82259235Sandreast}
83259235Sandreast
84259235Sandreaststatic __inline void
85259235Sandreastofw_restore_trap_vec(char *restore_trap_vec)
86259235Sandreast{
87266020Sian	if (!ofw_real_mode)
88259235Sandreast                return;
89259235Sandreast
90259235Sandreast	bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
91259235Sandreast	__syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
92259235Sandreast}
93259235Sandreast
9477957Sbenno/*
95151891Sgrehan * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
96151891Sgrehan */
97151891Sgrehanregister_t	ofw_sprg0_save;
98151891Sgrehan
99151891Sgrehanstatic __inline void
100151891Sgrehanofw_sprg_prepare(void)
101151891Sgrehan{
102266020Sian	if (ofw_real_mode)
103259235Sandreast		return;
104259235Sandreast
105151891Sgrehan	/*
106151891Sgrehan	 * Assume that interrupt are disabled at this point, or
107151891Sgrehan	 * SPRG1-3 could be trashed
108151891Sgrehan	 */
109151891Sgrehan	__asm __volatile("mfsprg0 %0\n\t"
110151891Sgrehan			 "mtsprg0 %1\n\t"
111151891Sgrehan	    		 "mtsprg1 %2\n\t"
112151891Sgrehan	    		 "mtsprg2 %3\n\t"
113151891Sgrehan			 "mtsprg3 %4\n\t"
114151891Sgrehan			 : "=&r"(ofw_sprg0_save)
115151891Sgrehan			 : "r"(ofmsr[1]),
116151891Sgrehan			 "r"(ofmsr[2]),
117151891Sgrehan			 "r"(ofmsr[3]),
118151891Sgrehan			 "r"(ofmsr[4]));
119151891Sgrehan}
120151891Sgrehan
121151891Sgrehanstatic __inline void
122151891Sgrehanofw_sprg_restore(void)
123151891Sgrehan{
124266020Sian#if 0
125266020Sian	if (ofw_real_mode)
126259235Sandreast		return;
127266020Sian#endif
128259235Sandreast
129151891Sgrehan	/*
130151891Sgrehan	 * Note that SPRG1-3 contents are irrelevant. They are scratch
131151891Sgrehan	 * registers used in the early portion of trap handling when
132151891Sgrehan	 * interrupts are disabled.
133151891Sgrehan	 *
134151891Sgrehan	 * PCPU data cannot be used until this routine is called !
135151891Sgrehan	 */
136151891Sgrehan	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
137151891Sgrehan}
138259235Sandreast#endif
139151891Sgrehan
140123370Sgrehanstatic int
141209975Snwhitehornparse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
14277957Sbenno{
143209975Snwhitehorn	cell_t address_cells, size_cells;
144222667Snwhitehorn	cell_t OFmem[4 * PHYS_AVAIL_SZ];
145209975Snwhitehorn	int sz, i, j;
146209975Snwhitehorn	int apple_hack_mode;
147190681Snwhitehorn	phandle_t phandle;
148190681Snwhitehorn
149209975Snwhitehorn	sz = 0;
150209975Snwhitehorn	apple_hack_mode = 0;
151190681Snwhitehorn
152190681Snwhitehorn	/*
153190681Snwhitehorn	 * Get #address-cells from root node, defaulting to 1 if it cannot
154190681Snwhitehorn	 * be found.
155190681Snwhitehorn	 */
156190681Snwhitehorn	phandle = OF_finddevice("/");
157190681Snwhitehorn	if (OF_getprop(phandle, "#address-cells", &address_cells,
158230398Snwhitehorn	    sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
159190681Snwhitehorn		address_cells = 1;
160209975Snwhitehorn	if (OF_getprop(phandle, "#size-cells", &size_cells,
161230398Snwhitehorn	    sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
162209975Snwhitehorn		size_cells = 1;
163209975Snwhitehorn
164209975Snwhitehorn	/*
16577957Sbenno	 * Get memory.
16677957Sbenno	 */
167222667Snwhitehorn	if (node == -1 || (sz = OF_getprop(node, prop,
168222667Snwhitehorn	    OFmem, sizeof(OFmem))) <= 0)
169209975Snwhitehorn		panic("Physical memory map not found");
170190681Snwhitehorn
171209975Snwhitehorn	i = 0;
172209975Snwhitehorn	j = 0;
173209975Snwhitehorn	while (i < sz/sizeof(cell_t)) {
174209975Snwhitehorn	      #ifndef __powerpc64__
175209975Snwhitehorn		/* On 32-bit PPC, ignore regions starting above 4 GB */
176209975Snwhitehorn		if (address_cells > 1 && OFmem[i] > 0) {
177209975Snwhitehorn			i += address_cells + size_cells;
178209975Snwhitehorn			continue;
179190681Snwhitehorn		}
180209975Snwhitehorn	      #endif
181190681Snwhitehorn
182209975Snwhitehorn		output[j].mr_start = OFmem[i++];
183209975Snwhitehorn		if (address_cells == 2) {
184209975Snwhitehorn			#ifdef __powerpc64__
185209975Snwhitehorn			output[j].mr_start <<= 32;
186209975Snwhitehorn			#endif
187209975Snwhitehorn			output[j].mr_start += OFmem[i++];
188190681Snwhitehorn		}
189209975Snwhitehorn
190209975Snwhitehorn		output[j].mr_size = OFmem[i++];
191209975Snwhitehorn		if (size_cells == 2) {
192209975Snwhitehorn			#ifdef __powerpc64__
193209975Snwhitehorn			output[j].mr_size <<= 32;
194209975Snwhitehorn			#endif
195209975Snwhitehorn			output[j].mr_size += OFmem[i++];
196209975Snwhitehorn		}
197190681Snwhitehorn
198209975Snwhitehorn	      #ifndef __powerpc64__
199209975Snwhitehorn		/*
200209975Snwhitehorn		 * Check for memory regions extending above 32-bit
201209975Snwhitehorn		 * memory space, and restrict them to stay there.
202209975Snwhitehorn		 */
203209975Snwhitehorn		if (((uint64_t)output[j].mr_start +
204209975Snwhitehorn		    (uint64_t)output[j].mr_size) >
205209975Snwhitehorn		    BUS_SPACE_MAXADDR_32BIT) {
206209975Snwhitehorn			output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
207209975Snwhitehorn			    output[j].mr_start;
208209975Snwhitehorn		}
209209975Snwhitehorn	      #endif
210190681Snwhitehorn
211209975Snwhitehorn		j++;
212209975Snwhitehorn	}
213209975Snwhitehorn	sz = j*sizeof(output[0]);
214209975Snwhitehorn
215209975Snwhitehorn	return (sz);
216209975Snwhitehorn}
217209975Snwhitehorn
218209975Snwhitehorn/*
219209975Snwhitehorn * This is called during powerpc_init, before the system is really initialized.
220209975Snwhitehorn * It shall provide the total and the available regions of RAM.
221209975Snwhitehorn * Both lists must have a zero-size entry as terminator.
222209975Snwhitehorn * The available regions need not take the kernel into account, but needs
223209975Snwhitehorn * to provide space for two additional entry beyond the terminating one.
224209975Snwhitehorn */
225209975Snwhitehornvoid
226266020Sianofw_mem_regions(struct mem_region *memp, int *memsz,
227266020Sian		struct mem_region *availp, int *availsz)
228209975Snwhitehorn{
229209975Snwhitehorn	phandle_t phandle;
230266020Sian	int asz, msz;
231266020Sian	int res;
232222667Snwhitehorn	char name[31];
233209975Snwhitehorn
234209975Snwhitehorn	asz = msz = 0;
235209975Snwhitehorn
236209975Snwhitehorn	/*
237222667Snwhitehorn	 * Get memory from all the /memory nodes.
238209975Snwhitehorn	 */
239222667Snwhitehorn	for (phandle = OF_child(OF_peer(0)); phandle != 0;
240222667Snwhitehorn	    phandle = OF_peer(phandle)) {
241222667Snwhitehorn		if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
242222667Snwhitehorn			continue;
243222667Snwhitehorn		if (strncmp(name, "memory", sizeof(name)) != 0)
244222667Snwhitehorn			continue;
245209975Snwhitehorn
246266020Sian		res = parse_ofw_memory(phandle, "reg", &memp[msz]);
247222667Snwhitehorn		msz += res/sizeof(struct mem_region);
248222667Snwhitehorn		if (OF_getproplen(phandle, "available") >= 0)
249222667Snwhitehorn			res = parse_ofw_memory(phandle, "available",
250266020Sian			    &availp[asz]);
251222667Snwhitehorn		else
252266020Sian			res = parse_ofw_memory(phandle, "reg", &availp[asz]);
253222667Snwhitehorn		asz += res/sizeof(struct mem_region);
254222667Snwhitehorn	}
255209975Snwhitehorn
256222667Snwhitehorn	*memsz = msz;
257266020Sian	*availsz = asz;
25877957Sbenno}
25977957Sbenno
260259235Sandreast#ifdef AIM
26177957Sbennovoid
262186347SnwhitehornOF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
26377957Sbenno{
264186347Snwhitehorn	if (ofmsr[0] & PSL_DR)
265186347Snwhitehorn		ofw_real_mode = 0;
266186347Snwhitehorn	else
267186347Snwhitehorn		ofw_real_mode = 1;
26877957Sbenno
269186347Snwhitehorn	fdt = fdt_ptr;
270215067Snwhitehorn
271215067Snwhitehorn	#ifdef FDT_DTB_STATIC
272215067Snwhitehorn	/* Check for a statically included blob */
273215067Snwhitehorn	if (fdt == NULL)
274215067Snwhitehorn		fdt = &fdt_static_dtb;
275215067Snwhitehorn	#endif
27677957Sbenno}
27777957Sbenno
278186347Snwhitehornboolean_t
279186347SnwhitehornOF_bootstrap()
280186347Snwhitehorn{
281186347Snwhitehorn	boolean_t status = FALSE;
282186347Snwhitehorn
283222613Snwhitehorn	if (openfirmware_entry != NULL) {
284209975Snwhitehorn		if (ofw_real_mode) {
285186347Snwhitehorn			status = OF_install(OFW_STD_REAL, 0);
286209975Snwhitehorn		} else {
287209975Snwhitehorn			#ifdef __powerpc64__
288209975Snwhitehorn			status = OF_install(OFW_STD_32BIT, 0);
289209975Snwhitehorn			#else
290186347Snwhitehorn			status = OF_install(OFW_STD_DIRECT, 0);
291209975Snwhitehorn			#endif
292209975Snwhitehorn		}
293186347Snwhitehorn
294186347Snwhitehorn		if (status != TRUE)
295186347Snwhitehorn			return status;
296186347Snwhitehorn
297186347Snwhitehorn		OF_init(openfirmware);
298215067Snwhitehorn	} else if (fdt != NULL) {
299186347Snwhitehorn		status = OF_install(OFW_FDT, 0);
300186347Snwhitehorn
301186347Snwhitehorn		if (status != TRUE)
302186347Snwhitehorn			return status;
303186347Snwhitehorn
304186347Snwhitehorn		OF_init(fdt);
305186347Snwhitehorn	}
306186347Snwhitehorn
307186347Snwhitehorn	return (status);
308186347Snwhitehorn}
309186347Snwhitehorn
310255910Snwhitehornvoid
311208172Snwhitehornofw_quiesce(void)
312208172Snwhitehorn{
313208172Snwhitehorn	struct {
314208172Snwhitehorn		cell_t name;
315208172Snwhitehorn		cell_t nargs;
316208172Snwhitehorn		cell_t nreturns;
317208172Snwhitehorn	} args;
318208172Snwhitehorn
319255910Snwhitehorn	KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
320208172Snwhitehorn
321255910Snwhitehorn	args.name = (cell_t)(uintptr_t)"quiesce";
322255910Snwhitehorn	args.nargs = 0;
323255910Snwhitehorn	args.nreturns = 0;
324255910Snwhitehorn	openfirmware(&args);
325208172Snwhitehorn}
326208172Snwhitehorn
327186347Snwhitehornstatic int
328208364Snwhitehornopenfirmware_core(void *args)
32977957Sbenno{
330209975Snwhitehorn	int		result;
331209975Snwhitehorn	register_t	oldmsr;
33277957Sbenno
333209975Snwhitehorn	/*
334209975Snwhitehorn	 * Turn off exceptions - we really don't want to end up
335215163Snwhitehorn	 * anywhere unexpected with PCPU set to something strange
336215163Snwhitehorn	 * or the stack pointer wrong.
337209975Snwhitehorn	 */
338209975Snwhitehorn	oldmsr = intr_disable();
33977957Sbenno
340151891Sgrehan	ofw_sprg_prepare();
341151891Sgrehan
342259235Sandreast	/* Save trap vectors */
343259235Sandreast	ofw_save_trap_vec(save_trap_of);
344259235Sandreast
345259235Sandreast	/* Restore initially saved trap vectors */
346259235Sandreast	ofw_restore_trap_vec(save_trap_init);
347259235Sandreast
348215163Snwhitehorn#if defined(AIM) && !defined(__powerpc64__)
349215163Snwhitehorn	/*
350215163Snwhitehorn	 * Clear battable[] translations
351215163Snwhitehorn	 */
352215163Snwhitehorn	if (!(cpu_features & PPC_FEATURE_64))
353215163Snwhitehorn		__asm __volatile("mtdbatu 2, %0\n"
354215163Snwhitehorn				 "mtdbatu 3, %0" : : "r" (0));
355215163Snwhitehorn	isync();
356215163Snwhitehorn#endif
357209975Snwhitehorn
358219428Snwhitehorn	result = ofwcall(args);
359259235Sandreast
360259235Sandreast	/* Restore trap vecotrs */
361259235Sandreast	ofw_restore_trap_vec(save_trap_of);
362259235Sandreast
363151891Sgrehan	ofw_sprg_restore();
364151891Sgrehan
365209975Snwhitehorn	intr_restore(oldmsr);
36677957Sbenno
367208364Snwhitehorn	return (result);
368208364Snwhitehorn}
369208364Snwhitehorn
370208364Snwhitehorn#ifdef SMP
371208364Snwhitehornstruct ofw_rv_args {
372208364Snwhitehorn	void *args;
373208364Snwhitehorn	int retval;
374208364Snwhitehorn	volatile int in_progress;
375208364Snwhitehorn};
376208364Snwhitehorn
377208364Snwhitehornstatic void
378208364Snwhitehornofw_rendezvous_dispatch(void *xargs)
379208364Snwhitehorn{
380208364Snwhitehorn	struct ofw_rv_args *rv_args = xargs;
381208364Snwhitehorn
382208364Snwhitehorn	/* NOTE: Interrupts are disabled here */
383208364Snwhitehorn
384208364Snwhitehorn	if (PCPU_GET(cpuid) == 0) {
385208364Snwhitehorn		/*
386208364Snwhitehorn		 * Execute all OF calls on CPU 0
387208364Snwhitehorn		 */
388208364Snwhitehorn		rv_args->retval = openfirmware_core(rv_args->args);
389208364Snwhitehorn		rv_args->in_progress = 0;
390208364Snwhitehorn	} else {
391208364Snwhitehorn		/*
392208364Snwhitehorn		 * Spin with interrupts off on other CPUs while OF has
393208364Snwhitehorn		 * control of the machine.
394208364Snwhitehorn		 */
395208364Snwhitehorn		while (rv_args->in_progress)
396208364Snwhitehorn			cpu_spinwait();
397208364Snwhitehorn	}
398208364Snwhitehorn}
399208364Snwhitehorn#endif
400208364Snwhitehorn
401208364Snwhitehornstatic int
402208364Snwhitehornopenfirmware(void *args)
403208364Snwhitehorn{
404208364Snwhitehorn	int result;
405208364Snwhitehorn	#ifdef SMP
406208364Snwhitehorn	struct ofw_rv_args rv_args;
407208364Snwhitehorn
408208364Snwhitehorn	rv_args.args = args;
409208364Snwhitehorn	rv_args.in_progress = 1;
410208364Snwhitehorn	smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
411208364Snwhitehorn	    smp_no_rendevous_barrier, &rv_args);
412208364Snwhitehorn	result = rv_args.retval;
413208364Snwhitehorn	#else
414208364Snwhitehorn	result = openfirmware_core(args);
415208364Snwhitehorn	#endif
416208364Snwhitehorn
41777957Sbenno	return (result);
41877957Sbenno}
41977957Sbenno
42077957Sbennovoid
421212054SnwhitehornOF_reboot()
422123353Sgallatin{
423212054Snwhitehorn	struct {
424212054Snwhitehorn		cell_t name;
425212054Snwhitehorn		cell_t nargs;
426212054Snwhitehorn		cell_t nreturns;
427212054Snwhitehorn		cell_t arg;
428212054Snwhitehorn	} args;
429123353Sgallatin
430212054Snwhitehorn	args.name = (cell_t)(uintptr_t)"interpret";
431212054Snwhitehorn	args.nargs = 1;
432212054Snwhitehorn	args.nreturns = 0;
433212054Snwhitehorn	args.arg = (cell_t)(uintptr_t)"reset-all";
434212054Snwhitehorn	openfirmware_core(&args); /* Don't do rendezvous! */
435123353Sgallatin
436123353Sgallatin	for (;;);	/* just in case */
437123353Sgallatin}
438123353Sgallatin
439259235Sandreast#endif /* AIM */
440259235Sandreast
441123353Sgallatinvoid
44299665SbennoOF_getetheraddr(device_t dev, u_char *addr)
44399665Sbenno{
44499665Sbenno	phandle_t	node;
44599665Sbenno
446183882Snwhitehorn	node = ofw_bus_get_node(dev);
44799665Sbenno	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
44899665Sbenno}
449133855Sssouhlal
450160714Smarcel/*
451165151Smarcel * Return a bus handle and bus tag that corresponds to the register
452165151Smarcel * numbered regno for the device referenced by the package handle
453165151Smarcel * dev. This function is intended to be used by console drivers in
454165151Smarcel * early boot only. It works by mapping the address of the device's
455165151Smarcel * register in the address space of its parent and recursively walk
456165151Smarcel * the device tree upward this way.
457160714Smarcel */
458165151Smarcelstatic void
459165151SmarcelOF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
460165151Smarcel{
461259235Sandreast	char type[64];
462165151Smarcel	uint32_t addr, size;
463165151Smarcel	int pci, res;
464165151Smarcel
465165151Smarcel	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
466165151Smarcel	if (res == -1)
467165151Smarcel		addr = 2;
468165151Smarcel	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
469165151Smarcel	if (res == -1)
470165151Smarcel		size = 1;
471165151Smarcel	pci = 0;
472165151Smarcel	if (addr == 3 && size == 2) {
473259235Sandreast		res = OF_getprop(node, "device_type", type, sizeof(type));
474165151Smarcel		if (res != -1) {
475259235Sandreast			type[sizeof(type) - 1] = '\0';
476259235Sandreast			pci = (strcmp(type, "pci") == 0) ? 1 : 0;
477165151Smarcel		}
478165151Smarcel	}
479165151Smarcel	if (addrp != NULL)
480165151Smarcel		*addrp = addr;
481165151Smarcel	if (sizep != NULL)
482165151Smarcel		*sizep = size;
483165151Smarcel	if (pcip != NULL)
484165151Smarcel		*pcip = pci;
485165151Smarcel}
486165151Smarcel
487133855Sssouhlalint
488165151SmarcelOF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
489160714Smarcel    bus_space_handle_t *handle)
490160714Smarcel{
491165151Smarcel	uint32_t cell[32];
492165151Smarcel	bus_addr_t addr, raddr, baddr;
493165151Smarcel	bus_size_t size, rsize;
494165151Smarcel	uint32_t c, nbridge, naddr, nsize;
495165151Smarcel	phandle_t bridge, parent;
496255904Snwhitehorn	u_int spc, rspc, prefetch;
497165151Smarcel	int pci, pcib, res;
498160714Smarcel
499165151Smarcel	/* Sanity checking. */
500165151Smarcel	if (dev == 0)
501165151Smarcel		return (EINVAL);
502165151Smarcel	bridge = OF_parent(dev);
503165151Smarcel	if (bridge == 0)
504165151Smarcel		return (EINVAL);
505165151Smarcel	if (regno < 0)
506165151Smarcel		return (EINVAL);
507165151Smarcel	if (tag == NULL || handle == NULL)
508165151Smarcel		return (EINVAL);
509165151Smarcel
510259235Sandreast	/* Assume big-endian unless we find a PCI device */
511259235Sandreast	*tag = &bs_be_tag;
512259235Sandreast
513165151Smarcel	/* Get the requested register. */
514165151Smarcel	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
515259235Sandreast	if (pci)
516259235Sandreast		*tag = &bs_le_tag;
517165151Smarcel	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
518165151Smarcel	    cell, sizeof(cell));
519165151Smarcel	if (res == -1)
520165151Smarcel		return (ENXIO);
521165151Smarcel	if (res % sizeof(cell[0]))
522165151Smarcel		return (ENXIO);
523165151Smarcel	res /= sizeof(cell[0]);
524165151Smarcel	regno *= naddr + nsize;
525165151Smarcel	if (regno + naddr + nsize > res)
526165151Smarcel		return (EINVAL);
527165151Smarcel	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
528255904Snwhitehorn	prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0;
529165151Smarcel	addr = 0;
530165151Smarcel	for (c = 0; c < naddr; c++)
531165151Smarcel		addr = ((uint64_t)addr << 32) | cell[regno++];
532165151Smarcel	size = 0;
533165151Smarcel	for (c = 0; c < nsize; c++)
534165151Smarcel		size = ((uint64_t)size << 32) | cell[regno++];
535165151Smarcel
536165151Smarcel	/*
537165151Smarcel	 * Map the address range in the bridge's decoding window as given
538165151Smarcel	 * by the "ranges" property. If a node doesn't have such property
539165151Smarcel	 * then no mapping is done.
540165151Smarcel	 */
541165151Smarcel	parent = OF_parent(bridge);
542165151Smarcel	while (parent != 0) {
543165151Smarcel		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
544259235Sandreast		if (pcib)
545259235Sandreast			*tag = &bs_le_tag;
546165151Smarcel		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
547165151Smarcel		if (res == -1)
548165151Smarcel			goto next;
549165151Smarcel		if (res % sizeof(cell[0]))
550165151Smarcel			return (ENXIO);
551165151Smarcel		res /= sizeof(cell[0]);
552165151Smarcel		regno = 0;
553165151Smarcel		while (regno < res) {
554165151Smarcel			rspc = (pci)
555165151Smarcel			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
556165151Smarcel			    : ~0;
557165151Smarcel			if (rspc != spc) {
558165151Smarcel				regno += naddr + nbridge + nsize;
559165151Smarcel				continue;
560165151Smarcel			}
561165151Smarcel			raddr = 0;
562165151Smarcel			for (c = 0; c < naddr; c++)
563165151Smarcel				raddr = ((uint64_t)raddr << 32) | cell[regno++];
564165151Smarcel			rspc = (pcib)
565165151Smarcel			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
566165151Smarcel			    : ~0;
567165151Smarcel			baddr = 0;
568165151Smarcel			for (c = 0; c < nbridge; c++)
569165151Smarcel				baddr = ((uint64_t)baddr << 32) | cell[regno++];
570165151Smarcel			rsize = 0;
571165151Smarcel			for (c = 0; c < nsize; c++)
572165151Smarcel				rsize = ((uint64_t)rsize << 32) | cell[regno++];
573165151Smarcel			if (addr < raddr || addr >= raddr + rsize)
574165151Smarcel				continue;
575165151Smarcel			addr = addr - raddr + baddr;
576165151Smarcel			if (rspc != ~0)
577165151Smarcel				spc = rspc;
578165151Smarcel		}
579165151Smarcel
580165151Smarcel	next:
581165151Smarcel		bridge = parent;
582165151Smarcel		parent = OF_parent(bridge);
583165151Smarcel		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
584165151Smarcel	}
585165151Smarcel
586255904Snwhitehorn	return (bus_space_map(*tag, addr, size,
587255904Snwhitehorn	    prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));
588160714Smarcel}
589160714Smarcel
590