1208747Sraj/*-
2208747Sraj * Copyright (c) 2009-2010 The FreeBSD Foundation
3208747Sraj * All rights reserved.
4208747Sraj *
5208747Sraj * This software was developed by Semihalf under sponsorship from
6208747Sraj * the FreeBSD Foundation.
7208747Sraj *
8208747Sraj * Redistribution and use in source and binary forms, with or without
9208747Sraj * modification, are permitted provided that the following conditions
10208747Sraj * are met:
11208747Sraj * 1. Redistributions of source code must retain the above copyright
12208747Sraj *    notice, this list of conditions and the following disclaimer.
13208747Sraj * 2. Redistributions in binary form must reproduce the above copyright
14208747Sraj *    notice, this list of conditions and the following disclaimer in the
15208747Sraj *    documentation and/or other materials provided with the distribution.
16208747Sraj *
17208747Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18208747Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19208747Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20208747Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21208747Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22208747Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23208747Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24208747Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25208747Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26208747Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27208747Sraj * SUCH DAMAGE.
28208747Sraj */
29208747Sraj
30208747Sraj#include <sys/cdefs.h>
31208747Sraj__FBSDID("$FreeBSD$");
32208747Sraj
33208747Sraj#include <sys/param.h>
34208747Sraj#include <sys/systm.h>
35208747Sraj#include <sys/kernel.h>
36208747Sraj#include <sys/module.h>
37208747Sraj#include <sys/bus.h>
38239274Sgonzo#include <sys/limits.h>
39208747Sraj
40208747Sraj#include <machine/fdt.h>
41208747Sraj#include <machine/resource.h>
42208747Sraj
43208747Sraj#include <dev/fdt/fdt_common.h>
44208747Sraj#include <dev/ofw/ofw_bus.h>
45208747Sraj#include <dev/ofw/ofw_bus_subr.h>
46208747Sraj#include <dev/ofw/openfirm.h>
47208747Sraj
48208747Sraj#include "ofw_bus_if.h"
49208747Sraj
50208747Sraj#ifdef DEBUG
51208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
52208747Sraj    printf(fmt,##args); } while (0)
53208747Sraj#else
54208747Sraj#define debugf(fmt, args...)
55208747Sraj#endif
56208747Sraj
57208747Sraj#define FDT_COMPAT_LEN	255
58208747Sraj#define FDT_TYPE_LEN	64
59208747Sraj
60208747Sraj#define FDT_REG_CELLS	4
61208747Sraj
62208747Srajvm_paddr_t fdt_immr_pa;
63208747Srajvm_offset_t fdt_immr_va;
64208747Srajvm_offset_t fdt_immr_size;
65208747Sraj
66257457Sbrooksstruct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head);
67257457Sbrooks
68208747Srajint
69239274Sgonzofdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
70208747Sraj{
71208747Sraj	pcell_t ranges[6], *rangesptr;
72208747Sraj	pcell_t addr_cells, size_cells, par_addr_cells;
73208747Sraj	int len, tuple_size, tuples;
74208747Sraj
75208747Sraj	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
76208747Sraj		return (ENXIO);
77208747Sraj	/*
78208747Sraj	 * Process 'ranges' property.
79208747Sraj	 */
80208747Sraj	par_addr_cells = fdt_parent_addr_cells(node);
81208747Sraj	if (par_addr_cells > 2)
82208747Sraj		return (ERANGE);
83208747Sraj
84208747Sraj	len = OF_getproplen(node, "ranges");
85208747Sraj	if (len > sizeof(ranges))
86208747Sraj		return (ENOMEM);
87239274Sgonzo	if (len == 0) {
88239274Sgonzo		*base = 0;
89239274Sgonzo		*size = ULONG_MAX;
90239274Sgonzo		return (0);
91239274Sgonzo	}
92208747Sraj
93239274Sgonzo	if (!(range_id < len))
94239274Sgonzo		return (ERANGE);
95239274Sgonzo
96208747Sraj	if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
97208747Sraj		return (EINVAL);
98208747Sraj
99208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
100208747Sraj	    size_cells);
101208747Sraj	tuples = len / tuple_size;
102208747Sraj
103208747Sraj	if (fdt_ranges_verify(ranges, tuples, par_addr_cells,
104208747Sraj	    addr_cells, size_cells)) {
105208747Sraj		return (ERANGE);
106208747Sraj	}
107239274Sgonzo	*base = 0;
108239274Sgonzo	*size = 0;
109239274Sgonzo	rangesptr = &ranges[range_id];
110208747Sraj
111239274Sgonzo	*base = fdt_data_get((void *)rangesptr, addr_cells);
112208747Sraj	rangesptr += addr_cells;
113239274Sgonzo	*base += fdt_data_get((void *)rangesptr, par_addr_cells);
114208747Sraj	rangesptr += par_addr_cells;
115239274Sgonzo	*size = fdt_data_get((void *)rangesptr, size_cells);
116239274Sgonzo	return (0);
117239274Sgonzo}
118208747Sraj
119239274Sgonzoint
120239274Sgonzofdt_immr_addr(vm_offset_t immr_va)
121239274Sgonzo{
122239274Sgonzo	phandle_t node;
123239274Sgonzo	u_long base, size;
124239274Sgonzo	int r;
125208747Sraj
126239274Sgonzo	/*
127239274Sgonzo	 * Try to access the SOC node directly i.e. through /aliases/.
128239274Sgonzo	 */
129239274Sgonzo	if ((node = OF_finddevice("soc")) != 0)
130239274Sgonzo		if (fdt_is_compatible_strict(node, "simple-bus"))
131239274Sgonzo			goto moveon;
132239274Sgonzo	/*
133239274Sgonzo	 * Find the node the long way.
134239274Sgonzo	 */
135239274Sgonzo	if ((node = OF_finddevice("/")) == 0)
136239274Sgonzo		return (ENXIO);
137239274Sgonzo
138239274Sgonzo	if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0)
139239274Sgonzo		return (ENXIO);
140239274Sgonzo
141239274Sgonzomoveon:
142239274Sgonzo	if ((r = fdt_get_range(node, 0, &base, &size)) == 0) {
143239274Sgonzo		fdt_immr_pa = base;
144239274Sgonzo		fdt_immr_va = immr_va;
145239274Sgonzo		fdt_immr_size = size;
146239274Sgonzo	}
147239274Sgonzo
148239274Sgonzo	return (r);
149208747Sraj}
150208747Sraj
151208747Sraj/*
152208747Sraj * This routine is an early-usage version of the ofw_bus_is_compatible() when
153208747Sraj * the ofw_bus I/F is not available (like early console routines and similar).
154208747Sraj * Note the buffer has to be on the stack since malloc() is usually not
155208747Sraj * available in such cases either.
156208747Sraj */
157208747Srajint
158208747Srajfdt_is_compatible(phandle_t node, const char *compatstr)
159208747Sraj{
160208747Sraj	char buf[FDT_COMPAT_LEN];
161208747Sraj	char *compat;
162208747Sraj	int len, onelen, l, rv;
163208747Sraj
164208747Sraj	if ((len = OF_getproplen(node, "compatible")) <= 0)
165208747Sraj		return (0);
166208747Sraj
167208747Sraj	compat = (char *)&buf;
168208747Sraj	bzero(compat, FDT_COMPAT_LEN);
169208747Sraj
170208747Sraj	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
171208747Sraj		return (0);
172208747Sraj
173208747Sraj	onelen = strlen(compatstr);
174208747Sraj	rv = 0;
175208747Sraj	while (len > 0) {
176208747Sraj		if (strncasecmp(compat, compatstr, onelen) == 0) {
177208747Sraj			/* Found it. */
178208747Sraj			rv = 1;
179208747Sraj			break;
180208747Sraj		}
181208747Sraj		/* Slide to the next sub-string. */
182208747Sraj		l = strlen(compat) + 1;
183208747Sraj		compat += l;
184208747Sraj		len -= l;
185208747Sraj	}
186208747Sraj
187208747Sraj	return (rv);
188208747Sraj}
189208747Sraj
190208747Srajint
191208747Srajfdt_is_compatible_strict(phandle_t node, const char *compatible)
192208747Sraj{
193208747Sraj	char compat[FDT_COMPAT_LEN];
194208747Sraj
195208747Sraj	if (OF_getproplen(node, "compatible") <= 0)
196208747Sraj		return (0);
197208747Sraj
198208747Sraj	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
199208747Sraj		return (0);
200208747Sraj
201208747Sraj	if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0)
202208747Sraj		/* This fits. */
203208747Sraj		return (1);
204208747Sraj
205208747Sraj	return (0);
206208747Sraj}
207208747Sraj
208208747Srajphandle_t
209208747Srajfdt_find_compatible(phandle_t start, const char *compat, int strict)
210208747Sraj{
211208747Sraj	phandle_t child;
212208747Sraj
213208747Sraj	/*
214208747Sraj	 * Traverse all children of 'start' node, and find first with
215208747Sraj	 * matching 'compatible' property.
216208747Sraj	 */
217208747Sraj	for (child = OF_child(start); child != 0; child = OF_peer(child))
218208747Sraj		if (fdt_is_compatible(child, compat)) {
219208747Sraj			if (strict)
220208747Sraj				if (!fdt_is_compatible_strict(child, compat))
221208747Sraj					continue;
222208747Sraj			return (child);
223208747Sraj		}
224208747Sraj	return (0);
225208747Sraj}
226208747Sraj
227208747Srajint
228208747Srajfdt_is_enabled(phandle_t node)
229208747Sraj{
230208747Sraj	char *stat;
231208747Sraj	int ena, len;
232208747Sraj
233208747Sraj	len = OF_getprop_alloc(node, "status", sizeof(char),
234208747Sraj	    (void **)&stat);
235208747Sraj
236208747Sraj	if (len <= 0)
237208747Sraj		/* It is OK if no 'status' property. */
238208747Sraj		return (1);
239208747Sraj
240208747Sraj	/* Anything other than 'okay' means disabled. */
241208747Sraj	ena = 0;
242208747Sraj	if (strncmp((char *)stat, "okay", len) == 0)
243208747Sraj		ena = 1;
244208747Sraj
245208747Sraj	free(stat, M_OFWPROP);
246208747Sraj	return (ena);
247208747Sraj}
248208747Sraj
249208747Srajint
250208747Srajfdt_is_type(phandle_t node, const char *typestr)
251208747Sraj{
252208747Sraj	char type[FDT_TYPE_LEN];
253208747Sraj
254208747Sraj	if (OF_getproplen(node, "device_type") <= 0)
255208747Sraj		return (0);
256208747Sraj
257208747Sraj	if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0)
258208747Sraj		return (0);
259208747Sraj
260208747Sraj	if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0)
261208747Sraj		/* This fits. */
262208747Sraj		return (1);
263208747Sraj
264208747Sraj	return (0);
265208747Sraj}
266208747Sraj
267208747Srajint
268208747Srajfdt_parent_addr_cells(phandle_t node)
269208747Sraj{
270208747Sraj	pcell_t addr_cells;
271208747Sraj
272208747Sraj	/* Find out #address-cells of the superior bus. */
273208747Sraj	if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells,
274208747Sraj	    sizeof(addr_cells)) <= 0)
275208747Sraj		addr_cells = 2;
276208747Sraj
277208747Sraj	return ((int)fdt32_to_cpu(addr_cells));
278208747Sraj}
279208747Sraj
280208747Srajint
281208747Srajfdt_data_verify(void *data, int cells)
282208747Sraj{
283208747Sraj	uint64_t d64;
284208747Sraj
285208747Sraj	if (cells > 1) {
286208747Sraj		d64 = fdt64_to_cpu(*((uint64_t *)data));
287208747Sraj		if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2)
288208747Sraj			return (ERANGE);
289208747Sraj	}
290208747Sraj
291208747Sraj	return (0);
292208747Sraj}
293208747Sraj
294208747Srajint
295208747Srajfdt_pm_is_enabled(phandle_t node)
296208747Sraj{
297208747Sraj	int ret;
298208747Sraj
299208747Sraj	ret = 1;
300208747Sraj
301208747Sraj#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
302208747Sraj	ret = fdt_pm(node);
303208747Sraj#endif
304208747Sraj	return (ret);
305208747Sraj}
306208747Sraj
307208747Sraju_long
308208747Srajfdt_data_get(void *data, int cells)
309208747Sraj{
310208747Sraj
311208747Sraj	if (cells == 1)
312208747Sraj		return (fdt32_to_cpu(*((uint32_t *)data)));
313208747Sraj
314208747Sraj	return (fdt64_to_cpu(*((uint64_t *)data)));
315208747Sraj}
316208747Sraj
317208747Srajint
318208747Srajfdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells)
319208747Sraj{
320208747Sraj	pcell_t cell;
321208747Sraj	int cell_size;
322208747Sraj
323208747Sraj	/*
324208747Sraj	 * Retrieve #{address,size}-cells.
325208747Sraj	 */
326208747Sraj	cell_size = sizeof(cell);
327208747Sraj	if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size)
328208747Sraj		cell = 2;
329208747Sraj	*addr_cells = fdt32_to_cpu((int)cell);
330208747Sraj
331208747Sraj	if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size)
332208747Sraj		cell = 1;
333208747Sraj	*size_cells = fdt32_to_cpu((int)cell);
334208747Sraj
335208747Sraj	if (*addr_cells > 3 || *size_cells > 2)
336208747Sraj		return (ERANGE);
337208747Sraj	return (0);
338208747Sraj}
339208747Sraj
340208747Srajint
341208747Srajfdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells,
342208747Sraj    int this_addr_cells, int this_size_cells)
343208747Sraj{
344208747Sraj	int i, rv, ulsz;
345208747Sraj
346208747Sraj	if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2)
347208747Sraj		return (ERANGE);
348208747Sraj
349208747Sraj	/*
350208747Sraj	 * This is the max size the resource manager can handle for addresses
351208747Sraj	 * and sizes.
352208747Sraj	 */
353208747Sraj	ulsz = sizeof(u_long);
354208747Sraj	if (par_addr_cells <= ulsz && this_addr_cells <= ulsz &&
355208747Sraj	    this_size_cells <= ulsz)
356208747Sraj		/* We can handle everything */
357208747Sraj		return (0);
358208747Sraj
359208747Sraj	rv = 0;
360208747Sraj	for (i = 0; i < tuples; i++) {
361208747Sraj
362208747Sraj		if (fdt_data_verify((void *)ranges, par_addr_cells))
363208747Sraj			goto err;
364208747Sraj		ranges += par_addr_cells;
365208747Sraj
366208747Sraj		if (fdt_data_verify((void *)ranges, this_addr_cells))
367208747Sraj			goto err;
368208747Sraj		ranges += this_addr_cells;
369208747Sraj
370208747Sraj		if (fdt_data_verify((void *)ranges, this_size_cells))
371208747Sraj			goto err;
372208747Sraj		ranges += this_size_cells;
373208747Sraj	}
374208747Sraj
375208747Sraj	return (0);
376208747Sraj
377208747Srajerr:
378208747Sraj	debugf("using address range >%d-bit not supported\n", ulsz * 8);
379208747Sraj	return (ERANGE);
380208747Sraj}
381208747Sraj
382208747Srajint
383208747Srajfdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start,
384208747Sraj    u_long *count)
385208747Sraj{
386208747Sraj
387208747Sraj	/* Address portion. */
388208747Sraj	if (fdt_data_verify((void *)data, addr_cells))
389208747Sraj		return (ERANGE);
390208747Sraj
391208747Sraj	*start = fdt_data_get((void *)data, addr_cells);
392208747Sraj	data += addr_cells;
393208747Sraj
394208747Sraj	/* Size portion. */
395208747Sraj	if (fdt_data_verify((void *)data, size_cells))
396208747Sraj		return (ERANGE);
397208747Sraj
398208747Sraj	*count = fdt_data_get((void *)data, size_cells);
399208747Sraj	return (0);
400208747Sraj}
401208747Sraj
402208747Srajint
403208747Srajfdt_regsize(phandle_t node, u_long *base, u_long *size)
404208747Sraj{
405208747Sraj	pcell_t reg[4];
406208747Sraj	int addr_cells, len, size_cells;
407208747Sraj
408208747Sraj	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
409208747Sraj		return (ENXIO);
410208747Sraj
411208747Sraj	if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
412208747Sraj		return (ENOMEM);
413208747Sraj
414208747Sraj	len = OF_getprop(node, "reg", &reg, sizeof(reg));
415208747Sraj	if (len <= 0)
416208747Sraj		return (EINVAL);
417208747Sraj
418208747Sraj	*base = fdt_data_get(&reg[0], addr_cells);
419208747Sraj	*size = fdt_data_get(&reg[addr_cells], size_cells);
420208747Sraj	return (0);
421208747Sraj}
422208747Sraj
423208747Srajint
424239274Sgonzofdt_reg_to_rl(phandle_t node, struct resource_list *rl)
425208747Sraj{
426248509Sray	u_long end, count, start;
427208747Sraj	pcell_t *reg, *regptr;
428208747Sraj	pcell_t addr_cells, size_cells;
429208747Sraj	int tuple_size, tuples;
430208747Sraj	int i, rv;
431239274Sgonzo	long busaddr, bussize;
432208747Sraj
433208747Sraj	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
434208747Sraj		return (ENXIO);
435240484Sgber	if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) {
436240484Sgber		busaddr = 0;
437240484Sgber		bussize = 0;
438240484Sgber	}
439208747Sraj
440208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
441208747Sraj	tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
442208747Sraj	debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
443208747Sraj	debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
444208747Sraj	if (tuples <= 0)
445208747Sraj		/* No 'reg' property in this node. */
446208747Sraj		return (0);
447208747Sraj
448208747Sraj	regptr = reg;
449208747Sraj	for (i = 0; i < tuples; i++) {
450208747Sraj
451248509Sray		rv = fdt_data_to_res(reg, addr_cells, size_cells, &start,
452248509Sray		    &count);
453208747Sraj		if (rv != 0) {
454208747Sraj			resource_list_free(rl);
455208747Sraj			goto out;
456208747Sraj		}
457208747Sraj		reg += addr_cells + size_cells;
458208747Sraj
459208747Sraj		/* Calculate address range relative to base. */
460239274Sgonzo		start += busaddr;
461248467Sray		end = start + count - 1;
462208747Sraj
463248467Sray		debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
464208747Sraj		    end, count);
465208747Sraj
466248467Sray		resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
467208747Sraj		    count);
468208747Sraj	}
469208747Sraj	rv = 0;
470208747Sraj
471208747Srajout:
472208747Sraj	free(regptr, M_OFWPROP);
473208747Sraj	return (rv);
474208747Sraj}
475208747Sraj
476208747Srajint
477208747Srajfdt_intr_decode(phandle_t intr_parent, pcell_t *intr, int *interrupt,
478208747Sraj    int *trig, int *pol)
479208747Sraj{
480208747Sraj	fdt_pic_decode_t intr_decode;
481208747Sraj	int i, rv;
482208747Sraj
483208747Sraj	for (i = 0; fdt_pic_table[i] != NULL; i++) {
484208747Sraj
485208747Sraj		/* XXX check if pic_handle has interrupt-controller prop? */
486208747Sraj
487208747Sraj		intr_decode = fdt_pic_table[i];
488208747Sraj		rv = intr_decode(intr_parent, intr, interrupt, trig, pol);
489208747Sraj
490208747Sraj		if (rv == 0)
491208747Sraj			/* This was recognized as our PIC and decoded. */
492208747Sraj			return (0);
493208747Sraj	}
494208747Sraj
495208747Sraj	return (ENXIO);
496208747Sraj}
497208747Sraj
498208747Srajint
499208747Srajfdt_intr_to_rl(phandle_t node, struct resource_list *rl,
500208747Sraj    struct fdt_sense_level *intr_sl)
501208747Sraj{
502208747Sraj	phandle_t intr_par;
503208747Sraj	ihandle_t iph;
504208747Sraj	pcell_t *intr;
505208747Sraj	pcell_t intr_cells;
506208747Sraj	int interrupt, trig, pol;
507218073Smarcel	int i, intr_num, irq, rv;
508208747Sraj
509208747Sraj	if (OF_getproplen(node, "interrupts") <= 0)
510208747Sraj		/* Node does not have 'interrupts' property. */
511208747Sraj		return (0);
512208747Sraj
513208747Sraj	/*
514208747Sraj	 * Find #interrupt-cells of the interrupt domain.
515208747Sraj	 */
516208747Sraj	if (OF_getprop(node, "interrupt-parent", &iph, sizeof(iph)) <= 0) {
517208747Sraj		debugf("no intr-parent phandle\n");
518208747Sraj		intr_par = OF_parent(node);
519208747Sraj	} else {
520208747Sraj		iph = fdt32_to_cpu(iph);
521208747Sraj		intr_par = OF_instance_to_package(iph);
522208747Sraj	}
523208747Sraj
524208747Sraj	if (OF_getprop(intr_par, "#interrupt-cells", &intr_cells,
525208747Sraj	    sizeof(intr_cells)) <= 0) {
526208747Sraj		debugf("no intr-cells defined, defaulting to 1\n");
527208747Sraj		intr_cells = 1;
528208747Sraj	}
529239689Sgonzo	else
530239689Sgonzo		intr_cells = fdt32_to_cpu(intr_cells);
531208747Sraj
532208747Sraj	intr_num = OF_getprop_alloc(node, "interrupts",
533208747Sraj	    intr_cells * sizeof(pcell_t), (void **)&intr);
534208747Sraj	if (intr_num <= 0 || intr_num > DI_MAX_INTR_NUM)
535208747Sraj		return (ERANGE);
536208747Sraj
537208747Sraj	rv = 0;
538208747Sraj	for (i = 0; i < intr_num; i++) {
539208747Sraj
540208747Sraj		interrupt = -1;
541208747Sraj		trig = pol = 0;
542208747Sraj
543208747Sraj		if (fdt_intr_decode(intr_par, &intr[i * intr_cells],
544208747Sraj		    &interrupt, &trig, &pol) != 0) {
545208747Sraj			rv = ENXIO;
546208747Sraj			goto out;
547208747Sraj		}
548208747Sraj
549208747Sraj		if (interrupt < 0) {
550208747Sraj			rv = ERANGE;
551208747Sraj			goto out;
552208747Sraj		}
553208747Sraj
554208747Sraj		debugf("decoded intr = %d, trig = %d, pol = %d\n", interrupt,
555208747Sraj		    trig, pol);
556208747Sraj
557209905Sraj		intr_sl[i].trig = trig;
558209905Sraj		intr_sl[i].pol = pol;
559208747Sraj
560218073Smarcel		irq = FDT_MAP_IRQ(intr_par, interrupt);
561218073Smarcel		resource_list_add(rl, SYS_RES_IRQ, i, irq, irq, 1);
562208747Sraj	}
563208747Sraj
564208747Srajout:
565208747Sraj	free(intr, M_OFWPROP);
566208747Sraj	return (rv);
567208747Sraj}
568208747Sraj
569208747Srajint
570232518Srajfdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
571208747Sraj{
572208747Sraj	phandle_t phy_node;
573208747Sraj	ihandle_t phy_ihandle;
574208747Sraj	pcell_t phy_handle, phy_reg;
575232518Sraj	uint32_t i;
576232518Sraj	device_t parent, child;
577208747Sraj
578208747Sraj	if (OF_getprop(node, "phy-handle", (void *)&phy_handle,
579208747Sraj	    sizeof(phy_handle)) <= 0)
580208747Sraj		return (ENXIO);
581208747Sraj
582208747Sraj	phy_ihandle = (ihandle_t)phy_handle;
583208747Sraj	phy_ihandle = fdt32_to_cpu(phy_ihandle);
584208747Sraj	phy_node = OF_instance_to_package(phy_ihandle);
585208747Sraj
586208747Sraj	if (OF_getprop(phy_node, "reg", (void *)&phy_reg,
587208747Sraj	    sizeof(phy_reg)) <= 0)
588208747Sraj		return (ENXIO);
589208747Sraj
590208747Sraj	*phy_addr = fdt32_to_cpu(phy_reg);
591232518Sraj
592232518Sraj	/*
593232518Sraj	 * Search for softc used to communicate with phy.
594232518Sraj	 */
595232518Sraj
596232518Sraj	/*
597232518Sraj	 * Step 1: Search for ancestor of the phy-node with a "phy-handle"
598232518Sraj	 * property set.
599232518Sraj	 */
600232518Sraj	phy_node = OF_parent(phy_node);
601232518Sraj	while (phy_node != 0) {
602232518Sraj		if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle,
603232518Sraj		    sizeof(phy_handle)) > 0)
604232518Sraj			break;
605232518Sraj		phy_node = OF_parent(phy_node);
606232518Sraj	}
607232518Sraj	if (phy_node == 0)
608232518Sraj		return (ENXIO);
609232518Sraj
610232518Sraj	/*
611232518Sraj	 * Step 2: For each device with the same parent and name as ours
612232518Sraj	 * compare its node with the one found in step 1, ancestor of phy
613232518Sraj	 * node (stored in phy_node).
614232518Sraj	 */
615232518Sraj	parent = device_get_parent(dev);
616232518Sraj	i = 0;
617232518Sraj	child = device_find_child(parent, device_get_name(dev), i);
618232518Sraj	while (child != NULL) {
619232518Sraj		if (ofw_bus_get_node(child) == phy_node)
620232518Sraj			break;
621232518Sraj		i++;
622232518Sraj		child = device_find_child(parent, device_get_name(dev), i);
623232518Sraj	}
624232518Sraj	if (child == NULL)
625232518Sraj		return (ENXIO);
626232518Sraj
627232518Sraj	/*
628232518Sraj	 * Use softc of the device found.
629232518Sraj	 */
630232518Sraj	*phy_sc = (void *)device_get_softc(child);
631232518Sraj
632208747Sraj	return (0);
633208747Sraj}
634208747Sraj
635208747Srajint
636243690Sgonzofdt_get_reserved_regions(struct mem_region *mr, int *mrcnt)
637243690Sgonzo{
638243690Sgonzo	pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS];
639243690Sgonzo	pcell_t *reservep;
640243690Sgonzo	phandle_t memory, root;
641243690Sgonzo	uint32_t memory_size;
642243690Sgonzo	int addr_cells, size_cells;
643243690Sgonzo	int i, max_size, res_len, rv, tuple_size, tuples;
644243690Sgonzo
645243690Sgonzo	max_size = sizeof(reserve);
646243690Sgonzo	root = OF_finddevice("/");
647243690Sgonzo	memory = OF_finddevice("/memory");
648243690Sgonzo	if (memory == -1) {
649243690Sgonzo		rv = ENXIO;
650243690Sgonzo		goto out;
651243690Sgonzo	}
652243690Sgonzo
653243690Sgonzo	if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
654243690Sgonzo	    &size_cells)) != 0)
655243690Sgonzo		goto out;
656243690Sgonzo
657243690Sgonzo	if (addr_cells > 2) {
658243690Sgonzo		rv = ERANGE;
659243690Sgonzo		goto out;
660243690Sgonzo	}
661243690Sgonzo
662243690Sgonzo	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
663243690Sgonzo
664243690Sgonzo	res_len = OF_getproplen(root, "memreserve");
665243690Sgonzo	if (res_len <= 0 || res_len > sizeof(reserve)) {
666243690Sgonzo		rv = ERANGE;
667243690Sgonzo		goto out;
668243690Sgonzo	}
669243690Sgonzo
670243690Sgonzo	if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) {
671243690Sgonzo		rv = ENXIO;
672243690Sgonzo		goto out;
673243690Sgonzo	}
674243690Sgonzo
675243690Sgonzo	memory_size = 0;
676243690Sgonzo	tuples = res_len / tuple_size;
677243690Sgonzo	reservep = (pcell_t *)&reserve;
678243690Sgonzo	for (i = 0; i < tuples; i++) {
679243690Sgonzo
680243690Sgonzo		rv = fdt_data_to_res(reservep, addr_cells, size_cells,
681243690Sgonzo			(u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
682243690Sgonzo
683243690Sgonzo		if (rv != 0)
684243690Sgonzo			goto out;
685243690Sgonzo
686243690Sgonzo		reservep += addr_cells + size_cells;
687243690Sgonzo	}
688243690Sgonzo
689243690Sgonzo	*mrcnt = i;
690243690Sgonzo	rv = 0;
691243690Sgonzoout:
692243690Sgonzo	return (rv);
693243690Sgonzo}
694243690Sgonzo
695243690Sgonzoint
696208747Srajfdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize)
697208747Sraj{
698208747Sraj	pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];
699208747Sraj	pcell_t *regp;
700208747Sraj	phandle_t memory;
701208747Sraj	uint32_t memory_size;
702208747Sraj	int addr_cells, size_cells;
703208747Sraj	int i, max_size, reg_len, rv, tuple_size, tuples;
704208747Sraj
705208747Sraj	max_size = sizeof(reg);
706208747Sraj	memory = OF_finddevice("/memory");
707228201Sjchandra	if (memory == -1) {
708208747Sraj		rv = ENXIO;
709208747Sraj		goto out;
710208747Sraj	}
711208747Sraj
712208747Sraj	if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
713208747Sraj	    &size_cells)) != 0)
714208747Sraj		goto out;
715208747Sraj
716208747Sraj	if (addr_cells > 2) {
717208747Sraj		rv = ERANGE;
718208747Sraj		goto out;
719208747Sraj	}
720208747Sraj
721208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
722208747Sraj	reg_len = OF_getproplen(memory, "reg");
723208747Sraj	if (reg_len <= 0 || reg_len > sizeof(reg)) {
724208747Sraj		rv = ERANGE;
725208747Sraj		goto out;
726208747Sraj	}
727208747Sraj
728208747Sraj	if (OF_getprop(memory, "reg", reg, reg_len) <= 0) {
729208747Sraj		rv = ENXIO;
730208747Sraj		goto out;
731208747Sraj	}
732208747Sraj
733208747Sraj	memory_size = 0;
734208747Sraj	tuples = reg_len / tuple_size;
735208747Sraj	regp = (pcell_t *)&reg;
736208747Sraj	for (i = 0; i < tuples; i++) {
737208747Sraj
738208747Sraj		rv = fdt_data_to_res(regp, addr_cells, size_cells,
739208747Sraj			(u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
740208747Sraj
741208747Sraj		if (rv != 0)
742208747Sraj			goto out;
743208747Sraj
744208747Sraj		regp += addr_cells + size_cells;
745208747Sraj		memory_size += mr[i].mr_size;
746208747Sraj	}
747208747Sraj
748208747Sraj	if (memory_size == 0) {
749208747Sraj		rv = ERANGE;
750208747Sraj		goto out;
751208747Sraj	}
752208747Sraj
753208747Sraj	*mrcnt = i;
754208747Sraj	*memsize = memory_size;
755208747Sraj	rv = 0;
756208747Srajout:
757208747Sraj	return (rv);
758208747Sraj}
759240485Sgber
760240485Sgberint
761240485Sgberfdt_get_unit(device_t dev)
762240485Sgber{
763240485Sgber	const char * name;
764240485Sgber
765240485Sgber	name = ofw_bus_get_name(dev);
766240485Sgber	name = strchr(name, '@') + 1;
767240485Sgber
768240485Sgber	return (strtol(name,NULL,0));
769240485Sgber}
770