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>
38208747Sraj
39208747Sraj#include <machine/fdt.h>
40208747Sraj#include <machine/resource.h>
41208747Sraj
42208747Sraj#include <dev/fdt/fdt_common.h>
43208747Sraj#include <dev/ofw/ofw_bus.h>
44208747Sraj#include <dev/ofw/ofw_bus_subr.h>
45208747Sraj#include <dev/ofw/openfirm.h>
46208747Sraj
47208747Sraj#include "ofw_bus_if.h"
48208747Sraj
49208747Sraj#ifdef DEBUG
50208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
51208747Sraj    printf(fmt,##args); } while (0)
52208747Sraj#else
53208747Sraj#define debugf(fmt, args...)
54208747Sraj#endif
55208747Sraj
56208747Sraj#define FDT_COMPAT_LEN	255
57208747Sraj#define FDT_TYPE_LEN	64
58208747Sraj
59208747Sraj#define FDT_REG_CELLS	4
60208747Sraj
61208747Srajvm_paddr_t fdt_immr_pa;
62208747Srajvm_offset_t fdt_immr_va;
63208747Srajvm_offset_t fdt_immr_size;
64208747Sraj
65208747Srajint
66210247Srajfdt_immr_addr(vm_offset_t immr_va)
67208747Sraj{
68208747Sraj	pcell_t ranges[6], *rangesptr;
69208747Sraj	phandle_t node;
70208747Sraj	u_long base, size;
71208747Sraj	pcell_t addr_cells, size_cells, par_addr_cells;
72208747Sraj	int len, tuple_size, tuples;
73208747Sraj
74208747Sraj	/*
75208747Sraj	 * Try to access the SOC node directly i.e. through /aliases/.
76208747Sraj	 */
77208747Sraj	if ((node = OF_finddevice("soc")) != 0)
78208747Sraj		if (fdt_is_compatible_strict(node, "simple-bus"))
79208747Sraj			goto moveon;
80208747Sraj	/*
81208747Sraj	 * Find the node the long way.
82208747Sraj	 */
83208747Sraj	if ((node = OF_finddevice("/")) == 0)
84208747Sraj		return (ENXIO);
85208747Sraj
86208747Sraj	if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0)
87208747Sraj		return (ENXIO);
88208747Sraj
89208747Srajmoveon:
90208747Sraj	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
91208747Sraj		return (ENXIO);
92208747Sraj	/*
93208747Sraj	 * Process 'ranges' property.
94208747Sraj	 */
95208747Sraj	par_addr_cells = fdt_parent_addr_cells(node);
96208747Sraj	if (par_addr_cells > 2)
97208747Sraj		return (ERANGE);
98208747Sraj
99208747Sraj	len = OF_getproplen(node, "ranges");
100208747Sraj	if (len > sizeof(ranges))
101208747Sraj		return (ENOMEM);
102208747Sraj
103208747Sraj	if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
104208747Sraj		return (EINVAL);
105208747Sraj
106208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
107208747Sraj	    size_cells);
108208747Sraj	tuples = len / tuple_size;
109208747Sraj
110208747Sraj	if (fdt_ranges_verify(ranges, tuples, par_addr_cells,
111208747Sraj	    addr_cells, size_cells)) {
112208747Sraj		return (ERANGE);
113208747Sraj	}
114208747Sraj	base = 0;
115208747Sraj	size = 0;
116208747Sraj	rangesptr = &ranges[0];
117208747Sraj
118208747Sraj	base = fdt_data_get((void *)rangesptr, addr_cells);
119208747Sraj	rangesptr += addr_cells;
120208747Sraj	base += fdt_data_get((void *)rangesptr, par_addr_cells);
121208747Sraj	rangesptr += par_addr_cells;
122208747Sraj	size = fdt_data_get((void *)rangesptr, size_cells);
123208747Sraj
124208747Sraj	fdt_immr_pa = base;
125210247Sraj	fdt_immr_va = immr_va;
126208747Sraj	fdt_immr_size = size;
127208747Sraj
128208747Sraj	return (0);
129208747Sraj}
130208747Sraj
131208747Sraj/*
132208747Sraj * This routine is an early-usage version of the ofw_bus_is_compatible() when
133208747Sraj * the ofw_bus I/F is not available (like early console routines and similar).
134208747Sraj * Note the buffer has to be on the stack since malloc() is usually not
135208747Sraj * available in such cases either.
136208747Sraj */
137208747Srajint
138208747Srajfdt_is_compatible(phandle_t node, const char *compatstr)
139208747Sraj{
140208747Sraj	char buf[FDT_COMPAT_LEN];
141208747Sraj	char *compat;
142208747Sraj	int len, onelen, l, rv;
143208747Sraj
144208747Sraj	if ((len = OF_getproplen(node, "compatible")) <= 0)
145208747Sraj		return (0);
146208747Sraj
147208747Sraj	compat = (char *)&buf;
148208747Sraj	bzero(compat, FDT_COMPAT_LEN);
149208747Sraj
150208747Sraj	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
151208747Sraj		return (0);
152208747Sraj
153208747Sraj	onelen = strlen(compatstr);
154208747Sraj	rv = 0;
155208747Sraj	while (len > 0) {
156208747Sraj		if (strncasecmp(compat, compatstr, onelen) == 0) {
157208747Sraj			/* Found it. */
158208747Sraj			rv = 1;
159208747Sraj			break;
160208747Sraj		}
161208747Sraj		/* Slide to the next sub-string. */
162208747Sraj		l = strlen(compat) + 1;
163208747Sraj		compat += l;
164208747Sraj		len -= l;
165208747Sraj	}
166208747Sraj
167208747Sraj	return (rv);
168208747Sraj}
169208747Sraj
170208747Srajint
171208747Srajfdt_is_compatible_strict(phandle_t node, const char *compatible)
172208747Sraj{
173208747Sraj	char compat[FDT_COMPAT_LEN];
174208747Sraj
175208747Sraj	if (OF_getproplen(node, "compatible") <= 0)
176208747Sraj		return (0);
177208747Sraj
178208747Sraj	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
179208747Sraj		return (0);
180208747Sraj
181208747Sraj	if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0)
182208747Sraj		/* This fits. */
183208747Sraj		return (1);
184208747Sraj
185208747Sraj	return (0);
186208747Sraj}
187208747Sraj
188208747Srajphandle_t
189208747Srajfdt_find_compatible(phandle_t start, const char *compat, int strict)
190208747Sraj{
191208747Sraj	phandle_t child;
192208747Sraj
193208747Sraj	/*
194208747Sraj	 * Traverse all children of 'start' node, and find first with
195208747Sraj	 * matching 'compatible' property.
196208747Sraj	 */
197208747Sraj	for (child = OF_child(start); child != 0; child = OF_peer(child))
198208747Sraj		if (fdt_is_compatible(child, compat)) {
199208747Sraj			if (strict)
200208747Sraj				if (!fdt_is_compatible_strict(child, compat))
201208747Sraj					continue;
202208747Sraj			return (child);
203208747Sraj		}
204208747Sraj	return (0);
205208747Sraj}
206208747Sraj
207208747Srajint
208208747Srajfdt_is_enabled(phandle_t node)
209208747Sraj{
210208747Sraj	char *stat;
211208747Sraj	int ena, len;
212208747Sraj
213208747Sraj	len = OF_getprop_alloc(node, "status", sizeof(char),
214208747Sraj	    (void **)&stat);
215208747Sraj
216208747Sraj	if (len <= 0)
217208747Sraj		/* It is OK if no 'status' property. */
218208747Sraj		return (1);
219208747Sraj
220208747Sraj	/* Anything other than 'okay' means disabled. */
221208747Sraj	ena = 0;
222208747Sraj	if (strncmp((char *)stat, "okay", len) == 0)
223208747Sraj		ena = 1;
224208747Sraj
225208747Sraj	free(stat, M_OFWPROP);
226208747Sraj	return (ena);
227208747Sraj}
228208747Sraj
229208747Srajint
230208747Srajfdt_is_type(phandle_t node, const char *typestr)
231208747Sraj{
232208747Sraj	char type[FDT_TYPE_LEN];
233208747Sraj
234208747Sraj	if (OF_getproplen(node, "device_type") <= 0)
235208747Sraj		return (0);
236208747Sraj
237208747Sraj	if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0)
238208747Sraj		return (0);
239208747Sraj
240208747Sraj	if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0)
241208747Sraj		/* This fits. */
242208747Sraj		return (1);
243208747Sraj
244208747Sraj	return (0);
245208747Sraj}
246208747Sraj
247208747Srajint
248208747Srajfdt_parent_addr_cells(phandle_t node)
249208747Sraj{
250208747Sraj	pcell_t addr_cells;
251208747Sraj
252208747Sraj	/* Find out #address-cells of the superior bus. */
253208747Sraj	if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells,
254208747Sraj	    sizeof(addr_cells)) <= 0)
255208747Sraj		addr_cells = 2;
256208747Sraj
257208747Sraj	return ((int)fdt32_to_cpu(addr_cells));
258208747Sraj}
259208747Sraj
260208747Srajint
261208747Srajfdt_data_verify(void *data, int cells)
262208747Sraj{
263208747Sraj	uint64_t d64;
264208747Sraj
265208747Sraj	if (cells > 1) {
266208747Sraj		d64 = fdt64_to_cpu(*((uint64_t *)data));
267208747Sraj		if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2)
268208747Sraj			return (ERANGE);
269208747Sraj	}
270208747Sraj
271208747Sraj	return (0);
272208747Sraj}
273208747Sraj
274208747Srajint
275208747Srajfdt_pm_is_enabled(phandle_t node)
276208747Sraj{
277208747Sraj	int ret;
278208747Sraj
279208747Sraj	ret = 1;
280208747Sraj
281208747Sraj#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
282208747Sraj	ret = fdt_pm(node);
283208747Sraj#endif
284208747Sraj	return (ret);
285208747Sraj}
286208747Sraj
287208747Sraju_long
288208747Srajfdt_data_get(void *data, int cells)
289208747Sraj{
290208747Sraj
291208747Sraj	if (cells == 1)
292208747Sraj		return (fdt32_to_cpu(*((uint32_t *)data)));
293208747Sraj
294208747Sraj	return (fdt64_to_cpu(*((uint64_t *)data)));
295208747Sraj}
296208747Sraj
297208747Srajint
298208747Srajfdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells)
299208747Sraj{
300208747Sraj	pcell_t cell;
301208747Sraj	int cell_size;
302208747Sraj
303208747Sraj	/*
304208747Sraj	 * Retrieve #{address,size}-cells.
305208747Sraj	 */
306208747Sraj	cell_size = sizeof(cell);
307208747Sraj	if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size)
308208747Sraj		cell = 2;
309208747Sraj	*addr_cells = fdt32_to_cpu((int)cell);
310208747Sraj
311208747Sraj	if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size)
312208747Sraj		cell = 1;
313208747Sraj	*size_cells = fdt32_to_cpu((int)cell);
314208747Sraj
315208747Sraj	if (*addr_cells > 3 || *size_cells > 2)
316208747Sraj		return (ERANGE);
317208747Sraj	return (0);
318208747Sraj}
319208747Sraj
320208747Srajint
321208747Srajfdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells,
322208747Sraj    int this_addr_cells, int this_size_cells)
323208747Sraj{
324208747Sraj	int i, rv, ulsz;
325208747Sraj
326208747Sraj	if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2)
327208747Sraj		return (ERANGE);
328208747Sraj
329208747Sraj	/*
330208747Sraj	 * This is the max size the resource manager can handle for addresses
331208747Sraj	 * and sizes.
332208747Sraj	 */
333208747Sraj	ulsz = sizeof(u_long);
334208747Sraj	if (par_addr_cells <= ulsz && this_addr_cells <= ulsz &&
335208747Sraj	    this_size_cells <= ulsz)
336208747Sraj		/* We can handle everything */
337208747Sraj		return (0);
338208747Sraj
339208747Sraj	rv = 0;
340208747Sraj	for (i = 0; i < tuples; i++) {
341208747Sraj
342208747Sraj		if (fdt_data_verify((void *)ranges, par_addr_cells))
343208747Sraj			goto err;
344208747Sraj		ranges += par_addr_cells;
345208747Sraj
346208747Sraj		if (fdt_data_verify((void *)ranges, this_addr_cells))
347208747Sraj			goto err;
348208747Sraj		ranges += this_addr_cells;
349208747Sraj
350208747Sraj		if (fdt_data_verify((void *)ranges, this_size_cells))
351208747Sraj			goto err;
352208747Sraj		ranges += this_size_cells;
353208747Sraj	}
354208747Sraj
355208747Sraj	return (0);
356208747Sraj
357208747Srajerr:
358208747Sraj	debugf("using address range >%d-bit not supported\n", ulsz * 8);
359208747Sraj	return (ERANGE);
360208747Sraj}
361208747Sraj
362208747Srajint
363208747Srajfdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start,
364208747Sraj    u_long *count)
365208747Sraj{
366208747Sraj
367208747Sraj	/* Address portion. */
368208747Sraj	if (fdt_data_verify((void *)data, addr_cells))
369208747Sraj		return (ERANGE);
370208747Sraj
371208747Sraj	*start = fdt_data_get((void *)data, addr_cells);
372208747Sraj	data += addr_cells;
373208747Sraj
374208747Sraj	/* Size portion. */
375208747Sraj	if (fdt_data_verify((void *)data, size_cells))
376208747Sraj		return (ERANGE);
377208747Sraj
378208747Sraj	*count = fdt_data_get((void *)data, size_cells);
379208747Sraj	return (0);
380208747Sraj}
381208747Sraj
382208747Srajint
383208747Srajfdt_regsize(phandle_t node, u_long *base, u_long *size)
384208747Sraj{
385208747Sraj	pcell_t reg[4];
386208747Sraj	int addr_cells, len, size_cells;
387208747Sraj
388208747Sraj	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
389208747Sraj		return (ENXIO);
390208747Sraj
391208747Sraj	if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
392208747Sraj		return (ENOMEM);
393208747Sraj
394208747Sraj	len = OF_getprop(node, "reg", &reg, sizeof(reg));
395208747Sraj	if (len <= 0)
396208747Sraj		return (EINVAL);
397208747Sraj
398208747Sraj	*base = fdt_data_get(&reg[0], addr_cells);
399208747Sraj	*size = fdt_data_get(&reg[addr_cells], size_cells);
400208747Sraj	return (0);
401208747Sraj}
402208747Sraj
403208747Srajint
404208747Srajfdt_reg_to_rl(phandle_t node, struct resource_list *rl, u_long base)
405208747Sraj{
406208747Sraj	u_long start, end, count;
407208747Sraj	pcell_t *reg, *regptr;
408208747Sraj	pcell_t addr_cells, size_cells;
409208747Sraj	int tuple_size, tuples;
410208747Sraj	int i, rv;
411208747Sraj
412208747Sraj	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
413208747Sraj		return (ENXIO);
414208747Sraj
415208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
416208747Sraj	tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
417208747Sraj	debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
418208747Sraj	debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
419208747Sraj	if (tuples <= 0)
420208747Sraj		/* No 'reg' property in this node. */
421208747Sraj		return (0);
422208747Sraj
423208747Sraj	regptr = reg;
424208747Sraj	for (i = 0; i < tuples; i++) {
425208747Sraj
426208747Sraj		rv = fdt_data_to_res(reg, addr_cells, size_cells, &start,
427208747Sraj		    &count);
428208747Sraj		if (rv != 0) {
429208747Sraj			resource_list_free(rl);
430208747Sraj			goto out;
431208747Sraj		}
432208747Sraj		reg += addr_cells + size_cells;
433208747Sraj
434208747Sraj		/* Calculate address range relative to base. */
435208747Sraj		start &= 0x000ffffful;
436208747Sraj		start = base + start;
437208747Sraj		end = start + count - 1;
438208747Sraj
439208747Sraj		debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
440208747Sraj		    end, count);
441208747Sraj
442208747Sraj		resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
443208747Sraj		    count);
444208747Sraj	}
445208747Sraj	rv = 0;
446208747Sraj
447208747Srajout:
448208747Sraj	free(regptr, M_OFWPROP);
449208747Sraj	return (rv);
450208747Sraj}
451208747Sraj
452208747Srajint
453208747Srajfdt_intr_decode(phandle_t intr_parent, pcell_t *intr, int *interrupt,
454208747Sraj    int *trig, int *pol)
455208747Sraj{
456208747Sraj	fdt_pic_decode_t intr_decode;
457208747Sraj	int i, rv;
458208747Sraj
459208747Sraj	for (i = 0; fdt_pic_table[i] != NULL; i++) {
460208747Sraj
461208747Sraj		/* XXX check if pic_handle has interrupt-controller prop? */
462208747Sraj
463208747Sraj		intr_decode = fdt_pic_table[i];
464208747Sraj		rv = intr_decode(intr_parent, intr, interrupt, trig, pol);
465208747Sraj
466208747Sraj		if (rv == 0)
467208747Sraj			/* This was recognized as our PIC and decoded. */
468208747Sraj			return (0);
469208747Sraj	}
470208747Sraj
471208747Sraj	return (ENXIO);
472208747Sraj}
473208747Sraj
474208747Srajint
475208747Srajfdt_intr_to_rl(phandle_t node, struct resource_list *rl,
476208747Sraj    struct fdt_sense_level *intr_sl)
477208747Sraj{
478208747Sraj	phandle_t intr_par;
479208747Sraj	ihandle_t iph;
480208747Sraj	pcell_t *intr;
481208747Sraj	pcell_t intr_cells;
482208747Sraj	int interrupt, trig, pol;
483218073Smarcel	int i, intr_num, irq, rv;
484208747Sraj
485208747Sraj	if (OF_getproplen(node, "interrupts") <= 0)
486208747Sraj		/* Node does not have 'interrupts' property. */
487208747Sraj		return (0);
488208747Sraj
489208747Sraj	/*
490208747Sraj	 * Find #interrupt-cells of the interrupt domain.
491208747Sraj	 */
492208747Sraj	if (OF_getprop(node, "interrupt-parent", &iph, sizeof(iph)) <= 0) {
493208747Sraj		debugf("no intr-parent phandle\n");
494208747Sraj		intr_par = OF_parent(node);
495208747Sraj	} else {
496208747Sraj		iph = fdt32_to_cpu(iph);
497208747Sraj		intr_par = OF_instance_to_package(iph);
498208747Sraj	}
499208747Sraj
500208747Sraj	if (OF_getprop(intr_par, "#interrupt-cells", &intr_cells,
501208747Sraj	    sizeof(intr_cells)) <= 0) {
502208747Sraj		debugf("no intr-cells defined, defaulting to 1\n");
503208747Sraj		intr_cells = 1;
504208747Sraj	}
505208747Sraj	intr_cells = fdt32_to_cpu(intr_cells);
506208747Sraj
507208747Sraj	intr_num = OF_getprop_alloc(node, "interrupts",
508208747Sraj	    intr_cells * sizeof(pcell_t), (void **)&intr);
509208747Sraj	if (intr_num <= 0 || intr_num > DI_MAX_INTR_NUM)
510208747Sraj		return (ERANGE);
511208747Sraj
512208747Sraj	rv = 0;
513208747Sraj	for (i = 0; i < intr_num; i++) {
514208747Sraj
515208747Sraj		interrupt = -1;
516208747Sraj		trig = pol = 0;
517208747Sraj
518208747Sraj		if (fdt_intr_decode(intr_par, &intr[i * intr_cells],
519208747Sraj		    &interrupt, &trig, &pol) != 0) {
520208747Sraj			rv = ENXIO;
521208747Sraj			goto out;
522208747Sraj		}
523208747Sraj
524208747Sraj		if (interrupt < 0) {
525208747Sraj			rv = ERANGE;
526208747Sraj			goto out;
527208747Sraj		}
528208747Sraj
529208747Sraj		debugf("decoded intr = %d, trig = %d, pol = %d\n", interrupt,
530208747Sraj		    trig, pol);
531208747Sraj
532209905Sraj		intr_sl[i].trig = trig;
533209905Sraj		intr_sl[i].pol = pol;
534208747Sraj
535218073Smarcel		irq = FDT_MAP_IRQ(intr_par, interrupt);
536218073Smarcel		resource_list_add(rl, SYS_RES_IRQ, i, irq, irq, 1);
537208747Sraj	}
538208747Sraj
539208747Srajout:
540208747Sraj	free(intr, M_OFWPROP);
541208747Sraj	return (rv);
542208747Sraj}
543208747Sraj
544208747Srajint
545233015Srajfdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
546208747Sraj{
547208747Sraj	phandle_t phy_node;
548208747Sraj	ihandle_t phy_ihandle;
549208747Sraj	pcell_t phy_handle, phy_reg;
550233015Sraj	uint32_t i;
551233015Sraj	device_t parent, child;
552208747Sraj
553208747Sraj	if (OF_getprop(node, "phy-handle", (void *)&phy_handle,
554208747Sraj	    sizeof(phy_handle)) <= 0)
555208747Sraj		return (ENXIO);
556208747Sraj
557208747Sraj	phy_ihandle = (ihandle_t)phy_handle;
558208747Sraj	phy_ihandle = fdt32_to_cpu(phy_ihandle);
559208747Sraj	phy_node = OF_instance_to_package(phy_ihandle);
560208747Sraj
561208747Sraj	if (OF_getprop(phy_node, "reg", (void *)&phy_reg,
562208747Sraj	    sizeof(phy_reg)) <= 0)
563208747Sraj		return (ENXIO);
564208747Sraj
565208747Sraj	*phy_addr = fdt32_to_cpu(phy_reg);
566233015Sraj
567233015Sraj	/*
568233015Sraj	 * Search for softc used to communicate with phy.
569233015Sraj	 */
570233015Sraj
571233015Sraj	/*
572233015Sraj	 * Step 1: Search for ancestor of the phy-node with a "phy-handle"
573233015Sraj	 * property set.
574233015Sraj	 */
575233015Sraj	phy_node = OF_parent(phy_node);
576233015Sraj	while (phy_node != 0) {
577233015Sraj		if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle,
578233015Sraj		    sizeof(phy_handle)) > 0)
579233015Sraj			break;
580233015Sraj		phy_node = OF_parent(phy_node);
581233015Sraj	}
582233015Sraj	if (phy_node == 0)
583233015Sraj		return (ENXIO);
584233015Sraj
585233015Sraj	/*
586233015Sraj	 * Step 2: For each device with the same parent and name as ours
587233015Sraj	 * compare its node with the one found in step 1, ancestor of phy
588233015Sraj	 * node (stored in phy_node).
589233015Sraj	 */
590233015Sraj	parent = device_get_parent(dev);
591233015Sraj	i = 0;
592233015Sraj	child = device_find_child(parent, device_get_name(dev), i);
593233015Sraj	while (child != NULL) {
594233015Sraj		if (ofw_bus_get_node(child) == phy_node)
595233015Sraj			break;
596233015Sraj		i++;
597233015Sraj		child = device_find_child(parent, device_get_name(dev), i);
598233015Sraj	}
599233015Sraj	if (child == NULL)
600233015Sraj		return (ENXIO);
601233015Sraj
602233015Sraj	/*
603233015Sraj	 * Use softc of the device found.
604233015Sraj	 */
605233015Sraj	*phy_sc = (void *)device_get_softc(child);
606233015Sraj
607208747Sraj	return (0);
608208747Sraj}
609208747Sraj
610208747Srajint
611208747Srajfdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize)
612208747Sraj{
613208747Sraj	pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];
614208747Sraj	pcell_t *regp;
615208747Sraj	phandle_t memory;
616208747Sraj	uint32_t memory_size;
617208747Sraj	int addr_cells, size_cells;
618208747Sraj	int i, max_size, reg_len, rv, tuple_size, tuples;
619208747Sraj
620208747Sraj	max_size = sizeof(reg);
621208747Sraj	memory = OF_finddevice("/memory");
622208747Sraj	if (memory <= 0) {
623208747Sraj		rv = ENXIO;
624208747Sraj		goto out;
625208747Sraj	}
626208747Sraj
627208747Sraj	if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
628208747Sraj	    &size_cells)) != 0)
629208747Sraj		goto out;
630208747Sraj
631208747Sraj	if (addr_cells > 2) {
632208747Sraj		rv = ERANGE;
633208747Sraj		goto out;
634208747Sraj	}
635208747Sraj
636208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
637208747Sraj	reg_len = OF_getproplen(memory, "reg");
638208747Sraj	if (reg_len <= 0 || reg_len > sizeof(reg)) {
639208747Sraj		rv = ERANGE;
640208747Sraj		goto out;
641208747Sraj	}
642208747Sraj
643208747Sraj	if (OF_getprop(memory, "reg", reg, reg_len) <= 0) {
644208747Sraj		rv = ENXIO;
645208747Sraj		goto out;
646208747Sraj	}
647208747Sraj
648208747Sraj	memory_size = 0;
649208747Sraj	tuples = reg_len / tuple_size;
650208747Sraj	regp = (pcell_t *)&reg;
651208747Sraj	for (i = 0; i < tuples; i++) {
652208747Sraj
653208747Sraj		rv = fdt_data_to_res(regp, addr_cells, size_cells,
654208747Sraj			(u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
655208747Sraj
656208747Sraj		if (rv != 0)
657208747Sraj			goto out;
658208747Sraj
659208747Sraj		regp += addr_cells + size_cells;
660208747Sraj		memory_size += mr[i].mr_size;
661208747Sraj	}
662208747Sraj
663208747Sraj	if (memory_size == 0) {
664208747Sraj		rv = ERANGE;
665208747Sraj		goto out;
666208747Sraj	}
667208747Sraj
668208747Sraj	*mrcnt = i;
669208747Sraj	*memsize = memory_size;
670208747Sraj	rv = 0;
671208747Srajout:
672208747Sraj	return (rv);
673208747Sraj}
674