fdt_common.c revision 233015
132785Speter/*-
232785Speter * Copyright (c) 2009-2010 The FreeBSD Foundation
332785Speter * All rights reserved.
432785Speter *
532785Speter * This software was developed by Semihalf under sponsorship from
632785Speter * the FreeBSD Foundation.
732785Speter *
832785Speter * Redistribution and use in source and binary forms, with or without
932785Speter * modification, are permitted provided that the following conditions
1032785Speter * are met:
1132785Speter * 1. Redistributions of source code must retain the above copyright
1232785Speter *    notice, this list of conditions and the following disclaimer.
1332785Speter * 2. Redistributions in binary form must reproduce the above copyright
1432785Speter *    notice, this list of conditions and the following disclaimer in the
1532785Speter *    documentation and/or other materials provided with the distribution.
1632785Speter *
1732785Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1832785Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1932785Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2032785Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2166525Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2266525Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2366525Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2432785Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2532785Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2632785Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2732785Speter * SUCH DAMAGE.
2832785Speter */
2932785Speter
3032785Speter#include <sys/cdefs.h>
3132785Speter__FBSDID("$FreeBSD: stable/9/sys/dev/fdt/fdt_common.c 233015 2012-03-15 22:15:06Z raj $");
3232785Speter
3332785Speter#include <sys/param.h>
3432785Speter#include <sys/systm.h>
3532785Speter#include <sys/kernel.h>
3632785Speter#include <sys/module.h>
3732785Speter#include <sys/bus.h>
3832785Speter
3932785Speter#include <machine/fdt.h>
4032785Speter#include <machine/resource.h>
4132785Speter
4232785Speter#include <dev/fdt/fdt_common.h>
4332785Speter#include <dev/ofw/ofw_bus.h>
4432785Speter#include <dev/ofw/ofw_bus_subr.h>
4532785Speter#include <dev/ofw/openfirm.h>
4632785Speter
4732785Speter#include "ofw_bus_if.h"
4832785Speter
4932785Speter#ifdef DEBUG
5032785Speter#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
5132785Speter    printf(fmt,##args); } while (0)
5232785Speter#else
5332785Speter#define debugf(fmt, args...)
5432785Speter#endif
5532785Speter
5632785Speter#define FDT_COMPAT_LEN	255
5732785Speter#define FDT_TYPE_LEN	64
5832785Speter
5932785Speter#define FDT_REG_CELLS	4
6032785Speter
6132785Spetervm_paddr_t fdt_immr_pa;
6232785Spetervm_offset_t fdt_immr_va;
6332785Spetervm_offset_t fdt_immr_size;
6432785Speter
6532785Speterint
6632785Speterfdt_immr_addr(vm_offset_t immr_va)
6732785Speter{
6832785Speter	pcell_t ranges[6], *rangesptr;
6932785Speter	phandle_t node;
7032785Speter	u_long base, size;
7132785Speter	pcell_t addr_cells, size_cells, par_addr_cells;
7232785Speter	int len, tuple_size, tuples;
7332785Speter
7432785Speter	/*
7532785Speter	 * Try to access the SOC node directly i.e. through /aliases/.
7632785Speter	 */
7732785Speter	if ((node = OF_finddevice("soc")) != 0)
7832785Speter		if (fdt_is_compatible_strict(node, "simple-bus"))
7932785Speter			goto moveon;
8032785Speter	/*
8132785Speter	 * Find the node the long way.
8232785Speter	 */
8332785Speter	if ((node = OF_finddevice("/")) == 0)
8432785Speter		return (ENXIO);
8532785Speter
8632785Speter	if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0)
8732785Speter		return (ENXIO);
8832785Speter
8932785Spetermoveon:
9032785Speter	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
9132785Speter		return (ENXIO);
9232785Speter	/*
9332785Speter	 * Process 'ranges' property.
9432785Speter	 */
9532785Speter	par_addr_cells = fdt_parent_addr_cells(node);
9632785Speter	if (par_addr_cells > 2)
9732785Speter		return (ERANGE);
9832785Speter
9932785Speter	len = OF_getproplen(node, "ranges");
10032785Speter	if (len > sizeof(ranges))
10132785Speter		return (ENOMEM);
10232785Speter
10332785Speter	if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
10432785Speter		return (EINVAL);
10532785Speter
10632785Speter	tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
10732785Speter	    size_cells);
10832785Speter	tuples = len / tuple_size;
10932785Speter
11032785Speter	if (fdt_ranges_verify(ranges, tuples, par_addr_cells,
11132785Speter	    addr_cells, size_cells)) {
11232785Speter		return (ERANGE);
11332785Speter	}
11432785Speter	base = 0;
11532785Speter	size = 0;
11632785Speter	rangesptr = &ranges[0];
11732785Speter
11832785Speter	base = fdt_data_get((void *)rangesptr, addr_cells);
11932785Speter	rangesptr += addr_cells;
12032785Speter	base += fdt_data_get((void *)rangesptr, par_addr_cells);
12132785Speter	rangesptr += par_addr_cells;
12232785Speter	size = fdt_data_get((void *)rangesptr, size_cells);
12332785Speter
12432785Speter	fdt_immr_pa = base;
12532785Speter	fdt_immr_va = immr_va;
12632785Speter	fdt_immr_size = size;
12732785Speter
12832785Speter	return (0);
12932785Speter}
13032785Speter
13132785Speter/*
13232785Speter * This routine is an early-usage version of the ofw_bus_is_compatible() when
13332785Speter * the ofw_bus I/F is not available (like early console routines and similar).
13432785Speter * Note the buffer has to be on the stack since malloc() is usually not
13532785Speter * available in such cases either.
13632785Speter */
13732785Speterint
13832785Speterfdt_is_compatible(phandle_t node, const char *compatstr)
13932785Speter{
14032785Speter	char buf[FDT_COMPAT_LEN];
14132785Speter	char *compat;
14232785Speter	int len, onelen, l, rv;
14332785Speter
14432785Speter	if ((len = OF_getproplen(node, "compatible")) <= 0)
14532785Speter		return (0);
14632785Speter
14732785Speter	compat = (char *)&buf;
14832785Speter	bzero(compat, FDT_COMPAT_LEN);
14932785Speter
15032785Speter	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
15132785Speter		return (0);
15232785Speter
15332785Speter	onelen = strlen(compatstr);
15432785Speter	rv = 0;
15532785Speter	while (len > 0) {
15632785Speter		if (strncasecmp(compat, compatstr, onelen) == 0) {
15732785Speter			/* Found it. */
15832785Speter			rv = 1;
15932785Speter			break;
16032785Speter		}
16132785Speter		/* Slide to the next sub-string. */
16232785Speter		l = strlen(compat) + 1;
16332785Speter		compat += l;
16432785Speter		len -= l;
16532785Speter	}
16632785Speter
16732785Speter	return (rv);
16832785Speter}
16932785Speter
17032785Speterint
17132785Speterfdt_is_compatible_strict(phandle_t node, const char *compatible)
17232785Speter{
17332785Speter	char compat[FDT_COMPAT_LEN];
17432785Speter
17532785Speter	if (OF_getproplen(node, "compatible") <= 0)
17632785Speter		return (0);
17732785Speter
17832785Speter	if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
17932785Speter		return (0);
18032785Speter
18132785Speter	if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0)
18232785Speter		/* This fits. */
18332785Speter		return (1);
18432785Speter
18532785Speter	return (0);
18632785Speter}
18732785Speter
18832785Speterphandle_t
18932785Speterfdt_find_compatible(phandle_t start, const char *compat, int strict)
19032785Speter{
19132785Speter	phandle_t child;
19232785Speter
19332785Speter	/*
19432785Speter	 * Traverse all children of 'start' node, and find first with
19532785Speter	 * matching 'compatible' property.
19632785Speter	 */
19732785Speter	for (child = OF_child(start); child != 0; child = OF_peer(child))
19832785Speter		if (fdt_is_compatible(child, compat)) {
19932785Speter			if (strict)
20032785Speter				if (!fdt_is_compatible_strict(child, compat))
20132785Speter					continue;
20232785Speter			return (child);
20332785Speter		}
20432785Speter	return (0);
20532785Speter}
20632785Speter
20732785Speterint
20832785Speterfdt_is_enabled(phandle_t node)
20932785Speter{
21032785Speter	char *stat;
21132785Speter	int ena, len;
21232785Speter
21332785Speter	len = OF_getprop_alloc(node, "status", sizeof(char),
21432785Speter	    (void **)&stat);
21532785Speter
21632785Speter	if (len <= 0)
21732785Speter		/* It is OK if no 'status' property. */
21832785Speter		return (1);
21932785Speter
22032785Speter	/* Anything other than 'okay' means disabled. */
22132785Speter	ena = 0;
22232785Speter	if (strncmp((char *)stat, "okay", len) == 0)
22332785Speter		ena = 1;
22432785Speter
22532785Speter	free(stat, M_OFWPROP);
22632785Speter	return (ena);
22732785Speter}
22832785Speter
22932785Speterint
23032785Speterfdt_is_type(phandle_t node, const char *typestr)
23132785Speter{
23232785Speter	char type[FDT_TYPE_LEN];
23332785Speter
23432785Speter	if (OF_getproplen(node, "device_type") <= 0)
23532785Speter		return (0);
23632785Speter
23732785Speter	if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0)
23832785Speter		return (0);
23932785Speter
24032785Speter	if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0)
24132785Speter		/* This fits. */
24232785Speter		return (1);
24332785Speter
24432785Speter	return (0);
24532785Speter}
24632785Speter
24732785Speterint
24832785Speterfdt_parent_addr_cells(phandle_t node)
24932785Speter{
25032785Speter	pcell_t addr_cells;
25132785Speter
25232785Speter	/* Find out #address-cells of the superior bus. */
25332785Speter	if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells,
25432785Speter	    sizeof(addr_cells)) <= 0)
25532785Speter		addr_cells = 2;
25632785Speter
25732785Speter	return ((int)fdt32_to_cpu(addr_cells));
25832785Speter}
25932785Speter
26032785Speterint
26132785Speterfdt_data_verify(void *data, int cells)
26232785Speter{
26332785Speter	uint64_t d64;
26432785Speter
26532785Speter	if (cells > 1) {
26632785Speter		d64 = fdt64_to_cpu(*((uint64_t *)data));
26732785Speter		if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2)
26832785Speter			return (ERANGE);
26932785Speter	}
27032785Speter
27132785Speter	return (0);
27232785Speter}
27332785Speter
27432785Speterint
27532785Speterfdt_pm_is_enabled(phandle_t node)
27632785Speter{
27732785Speter	int ret;
27832785Speter
27932785Speter	ret = 1;
28032785Speter
28132785Speter#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
28232785Speter	ret = fdt_pm(node);
28332785Speter#endif
28432785Speter	return (ret);
28532785Speter}
28632785Speter
28732785Speteru_long
28832785Speterfdt_data_get(void *data, int cells)
28932785Speter{
29032785Speter
29132785Speter	if (cells == 1)
29232785Speter		return (fdt32_to_cpu(*((uint32_t *)data)));
29332785Speter
29432785Speter	return (fdt64_to_cpu(*((uint64_t *)data)));
29532785Speter}
29632785Speter
29732785Speterint
29832785Speterfdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells)
29932785Speter{
30032785Speter	pcell_t cell;
30132785Speter	int cell_size;
30232785Speter
30332785Speter	/*
30432785Speter	 * Retrieve #{address,size}-cells.
30532785Speter	 */
30632785Speter	cell_size = sizeof(cell);
30732785Speter	if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size)
30832785Speter		cell = 2;
30932785Speter	*addr_cells = fdt32_to_cpu((int)cell);
31032785Speter
31132785Speter	if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size)
31232785Speter		cell = 1;
31332785Speter	*size_cells = fdt32_to_cpu((int)cell);
31432785Speter
31532785Speter	if (*addr_cells > 3 || *size_cells > 2)
31632785Speter		return (ERANGE);
31732785Speter	return (0);
31832785Speter}
31932785Speter
32032785Speterint
32132785Speterfdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells,
32232785Speter    int this_addr_cells, int this_size_cells)
32332785Speter{
32432785Speter	int i, rv, ulsz;
32532785Speter
32632785Speter	if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2)
32732785Speter		return (ERANGE);
32832785Speter
32932785Speter	/*
33032785Speter	 * This is the max size the resource manager can handle for addresses
33132785Speter	 * and sizes.
33232785Speter	 */
33332785Speter	ulsz = sizeof(u_long);
33432785Speter	if (par_addr_cells <= ulsz && this_addr_cells <= ulsz &&
33532785Speter	    this_size_cells <= ulsz)
33632785Speter		/* We can handle everything */
33732785Speter		return (0);
33832785Speter
33932785Speter	rv = 0;
34032785Speter	for (i = 0; i < tuples; i++) {
34132785Speter
34232785Speter		if (fdt_data_verify((void *)ranges, par_addr_cells))
34332785Speter			goto err;
34432785Speter		ranges += par_addr_cells;
34532785Speter
34632785Speter		if (fdt_data_verify((void *)ranges, this_addr_cells))
34732785Speter			goto err;
34832785Speter		ranges += this_addr_cells;
34932785Speter
35032785Speter		if (fdt_data_verify((void *)ranges, this_size_cells))
35132785Speter			goto err;
35232785Speter		ranges += this_size_cells;
35332785Speter	}
35432785Speter
35532785Speter	return (0);
35632785Speter
35732785Spetererr:
35832785Speter	debugf("using address range >%d-bit not supported\n", ulsz * 8);
35932785Speter	return (ERANGE);
36032785Speter}
36132785Speter
36232785Speterint
36332785Speterfdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start,
36432785Speter    u_long *count)
36532785Speter{
36632785Speter
36732785Speter	/* Address portion. */
36832785Speter	if (fdt_data_verify((void *)data, addr_cells))
36932785Speter		return (ERANGE);
37032785Speter
37132785Speter	*start = fdt_data_get((void *)data, addr_cells);
37232785Speter	data += addr_cells;
37332785Speter
37432785Speter	/* Size portion. */
37532785Speter	if (fdt_data_verify((void *)data, size_cells))
37632785Speter		return (ERANGE);
37732785Speter
37832785Speter	*count = fdt_data_get((void *)data, size_cells);
37932785Speter	return (0);
38032785Speter}
38132785Speter
38232785Speterint
38332785Speterfdt_regsize(phandle_t node, u_long *base, u_long *size)
38432785Speter{
38532785Speter	pcell_t reg[4];
38632785Speter	int addr_cells, len, size_cells;
38732785Speter
38832785Speter	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
38932785Speter		return (ENXIO);
39032785Speter
39132785Speter	if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
39232785Speter		return (ENOMEM);
39332785Speter
39432785Speter	len = OF_getprop(node, "reg", &reg, sizeof(reg));
39532785Speter	if (len <= 0)
39632785Speter		return (EINVAL);
39732785Speter
39832785Speter	*base = fdt_data_get(&reg[0], addr_cells);
39932785Speter	*size = fdt_data_get(&reg[addr_cells], size_cells);
40032785Speter	return (0);
40132785Speter}
40232785Speter
40332785Speterint
40432785Speterfdt_reg_to_rl(phandle_t node, struct resource_list *rl, u_long base)
40532785Speter{
40632785Speter	u_long start, end, count;
40732785Speter	pcell_t *reg, *regptr;
40832785Speter	pcell_t addr_cells, size_cells;
40932785Speter	int tuple_size, tuples;
41032785Speter	int i, rv;
41132785Speter
41232785Speter	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
41332785Speter		return (ENXIO);
41432785Speter
41532785Speter	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
41632785Speter	tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
41732785Speter	debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
41832785Speter	debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
41932785Speter	if (tuples <= 0)
42032785Speter		/* No 'reg' property in this node. */
42132785Speter		return (0);
42232785Speter
42332785Speter	regptr = reg;
42432785Speter	for (i = 0; i < tuples; i++) {
42532785Speter
42632785Speter		rv = fdt_data_to_res(reg, addr_cells, size_cells, &start,
42732785Speter		    &count);
42832785Speter		if (rv != 0) {
42932785Speter			resource_list_free(rl);
43032785Speter			goto out;
43132785Speter		}
43232785Speter		reg += addr_cells + size_cells;
43332785Speter
43432785Speter		/* Calculate address range relative to base. */
43532785Speter		start &= 0x000ffffful;
43632785Speter		start = base + start;
43732785Speter		end = start + count - 1;
43832785Speter
43932785Speter		debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
44032785Speter		    end, count);
44132785Speter
44232785Speter		resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
44332785Speter		    count);
44432785Speter	}
44532785Speter	rv = 0;
44632785Speter
44732785Speterout:
44832785Speter	free(regptr, M_OFWPROP);
44932785Speter	return (rv);
45032785Speter}
45132785Speter
45232785Speterint
45332785Speterfdt_intr_decode(phandle_t intr_parent, pcell_t *intr, int *interrupt,
45432785Speter    int *trig, int *pol)
45532785Speter{
45632785Speter	fdt_pic_decode_t intr_decode;
45732785Speter	int i, rv;
45832785Speter
45932785Speter	for (i = 0; fdt_pic_table[i] != NULL; i++) {
46032785Speter
46132785Speter		/* XXX check if pic_handle has interrupt-controller prop? */
46232785Speter
46332785Speter		intr_decode = fdt_pic_table[i];
46432785Speter		rv = intr_decode(intr_parent, intr, interrupt, trig, pol);
46532785Speter
46632785Speter		if (rv == 0)
46732785Speter			/* This was recognized as our PIC and decoded. */
46832785Speter			return (0);
46932785Speter	}
47032785Speter
47132785Speter	return (ENXIO);
47232785Speter}
47332785Speter
47432785Speterint
47532785Speterfdt_intr_to_rl(phandle_t node, struct resource_list *rl,
47632785Speter    struct fdt_sense_level *intr_sl)
47732785Speter{
47832785Speter	phandle_t intr_par;
47932785Speter	ihandle_t iph;
48032785Speter	pcell_t *intr;
48132785Speter	pcell_t intr_cells;
48232785Speter	int interrupt, trig, pol;
48332785Speter	int i, intr_num, irq, rv;
48432785Speter
48532785Speter	if (OF_getproplen(node, "interrupts") <= 0)
48632785Speter		/* Node does not have 'interrupts' property. */
48732785Speter		return (0);
48832785Speter
48932785Speter	/*
49032785Speter	 * Find #interrupt-cells of the interrupt domain.
49132785Speter	 */
49232785Speter	if (OF_getprop(node, "interrupt-parent", &iph, sizeof(iph)) <= 0) {
49332785Speter		debugf("no intr-parent phandle\n");
49432785Speter		intr_par = OF_parent(node);
49532785Speter	} else {
49632785Speter		iph = fdt32_to_cpu(iph);
49732785Speter		intr_par = OF_instance_to_package(iph);
49832785Speter	}
49932785Speter
50032785Speter	if (OF_getprop(intr_par, "#interrupt-cells", &intr_cells,
50132785Speter	    sizeof(intr_cells)) <= 0) {
50232785Speter		debugf("no intr-cells defined, defaulting to 1\n");
50332785Speter		intr_cells = 1;
50432785Speter	}
50532785Speter	intr_cells = fdt32_to_cpu(intr_cells);
50632785Speter
50732785Speter	intr_num = OF_getprop_alloc(node, "interrupts",
50832785Speter	    intr_cells * sizeof(pcell_t), (void **)&intr);
50932785Speter	if (intr_num <= 0 || intr_num > DI_MAX_INTR_NUM)
51032785Speter		return (ERANGE);
51132785Speter
51232785Speter	rv = 0;
51332785Speter	for (i = 0; i < intr_num; i++) {
51432785Speter
51532785Speter		interrupt = -1;
51632785Speter		trig = pol = 0;
51732785Speter
51832785Speter		if (fdt_intr_decode(intr_par, &intr[i * intr_cells],
51932785Speter		    &interrupt, &trig, &pol) != 0) {
52032785Speter			rv = ENXIO;
52132785Speter			goto out;
52232785Speter		}
52332785Speter
52432785Speter		if (interrupt < 0) {
52532785Speter			rv = ERANGE;
52632785Speter			goto out;
52732785Speter		}
52832785Speter
52932785Speter		debugf("decoded intr = %d, trig = %d, pol = %d\n", interrupt,
53032785Speter		    trig, pol);
53132785Speter
53232785Speter		intr_sl[i].trig = trig;
53332785Speter		intr_sl[i].pol = pol;
53432785Speter
53532785Speter		irq = FDT_MAP_IRQ(intr_par, interrupt);
53632785Speter		resource_list_add(rl, SYS_RES_IRQ, i, irq, irq, 1);
53732785Speter	}
53832785Speter
53932785Speterout:
54032785Speter	free(intr, M_OFWPROP);
54132785Speter	return (rv);
54232785Speter}
54332785Speter
54432785Speterint
54532785Speterfdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
54632785Speter{
54732785Speter	phandle_t phy_node;
54832785Speter	ihandle_t phy_ihandle;
54932785Speter	pcell_t phy_handle, phy_reg;
55032785Speter	uint32_t i;
55132785Speter	device_t parent, child;
55232785Speter
55332785Speter	if (OF_getprop(node, "phy-handle", (void *)&phy_handle,
55432785Speter	    sizeof(phy_handle)) <= 0)
55532785Speter		return (ENXIO);
55632785Speter
55732785Speter	phy_ihandle = (ihandle_t)phy_handle;
55832785Speter	phy_ihandle = fdt32_to_cpu(phy_ihandle);
55932785Speter	phy_node = OF_instance_to_package(phy_ihandle);
56032785Speter
56132785Speter	if (OF_getprop(phy_node, "reg", (void *)&phy_reg,
56232785Speter	    sizeof(phy_reg)) <= 0)
56332785Speter		return (ENXIO);
56432785Speter
56532785Speter	*phy_addr = fdt32_to_cpu(phy_reg);
56632785Speter
56732785Speter	/*
56832785Speter	 * Search for softc used to communicate with phy.
56932785Speter	 */
57032785Speter
57132785Speter	/*
57232785Speter	 * Step 1: Search for ancestor of the phy-node with a "phy-handle"
57332785Speter	 * property set.
57432785Speter	 */
57532785Speter	phy_node = OF_parent(phy_node);
57632785Speter	while (phy_node != 0) {
57732785Speter		if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle,
57832785Speter		    sizeof(phy_handle)) > 0)
57932785Speter			break;
58032785Speter		phy_node = OF_parent(phy_node);
58132785Speter	}
58232785Speter	if (phy_node == 0)
58332785Speter		return (ENXIO);
58432785Speter
58532785Speter	/*
58632785Speter	 * Step 2: For each device with the same parent and name as ours
58732785Speter	 * compare its node with the one found in step 1, ancestor of phy
58832785Speter	 * node (stored in phy_node).
58932785Speter	 */
59032785Speter	parent = device_get_parent(dev);
59132785Speter	i = 0;
59232785Speter	child = device_find_child(parent, device_get_name(dev), i);
59332785Speter	while (child != NULL) {
59432785Speter		if (ofw_bus_get_node(child) == phy_node)
59532785Speter			break;
59632785Speter		i++;
59732785Speter		child = device_find_child(parent, device_get_name(dev), i);
59832785Speter	}
59932785Speter	if (child == NULL)
60032785Speter		return (ENXIO);
60132785Speter
60232785Speter	/*
60332785Speter	 * Use softc of the device found.
60432785Speter	 */
60532785Speter	*phy_sc = (void *)device_get_softc(child);
60632785Speter
60732785Speter	return (0);
60832785Speter}
60932785Speter
61032785Speterint
61132785Speterfdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize)
61232785Speter{
61332785Speter	pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];
61432785Speter	pcell_t *regp;
61532785Speter	phandle_t memory;
61632785Speter	uint32_t memory_size;
61732785Speter	int addr_cells, size_cells;
61832785Speter	int i, max_size, reg_len, rv, tuple_size, tuples;
61932785Speter
62032785Speter	max_size = sizeof(reg);
62132785Speter	memory = OF_finddevice("/memory");
62232785Speter	if (memory <= 0) {
62332785Speter		rv = ENXIO;
62432785Speter		goto out;
62532785Speter	}
62632785Speter
62732785Speter	if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
62832785Speter	    &size_cells)) != 0)
62932785Speter		goto out;
63032785Speter
63132785Speter	if (addr_cells > 2) {
63232785Speter		rv = ERANGE;
63332785Speter		goto out;
63432785Speter	}
63532785Speter
63632785Speter	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
63732785Speter	reg_len = OF_getproplen(memory, "reg");
63832785Speter	if (reg_len <= 0 || reg_len > sizeof(reg)) {
63932785Speter		rv = ERANGE;
64032785Speter		goto out;
64132785Speter	}
64232785Speter
64332785Speter	if (OF_getprop(memory, "reg", reg, reg_len) <= 0) {
64432785Speter		rv = ENXIO;
64532785Speter		goto out;
64632785Speter	}
64732785Speter
64832785Speter	memory_size = 0;
64932785Speter	tuples = reg_len / tuple_size;
65032785Speter	regp = (pcell_t *)&reg;
65132785Speter	for (i = 0; i < tuples; i++) {
65232785Speter
65332785Speter		rv = fdt_data_to_res(regp, addr_cells, size_cells,
65432785Speter			(u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
65532785Speter
65632785Speter		if (rv != 0)
65732785Speter			goto out;
65832785Speter
65932785Speter		regp += addr_cells + size_cells;
66032785Speter		memory_size += mr[i].mr_size;
66132785Speter	}
66232785Speter
66332785Speter	if (memory_size == 0) {
66432785Speter		rv = ERANGE;
66532785Speter		goto out;
66632785Speter	}
66732785Speter
66832785Speter	*mrcnt = i;
66932785Speter	*memsize = memory_size;
67032785Speter	rv = 0;
67132785Speterout:
67232785Speter	return (rv);
67332785Speter}
67432785Speter