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", ®, sizeof(reg)); 39532785Speter if (len <= 0) 39632785Speter return (EINVAL); 39732785Speter 39832785Speter *base = fdt_data_get(®[0], addr_cells); 39932785Speter *size = fdt_data_get(®[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 **)®); 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 *)® 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