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/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 65257457Sbrooksstruct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); 66257457Sbrooks 67208747Srajint 68239274Sgonzofdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) 69208747Sraj{ 70208747Sraj pcell_t ranges[6], *rangesptr; 71208747Sraj pcell_t addr_cells, size_cells, par_addr_cells; 72208747Sraj int len, tuple_size, tuples; 73208747Sraj 74208747Sraj if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 75208747Sraj return (ENXIO); 76208747Sraj /* 77208747Sraj * Process 'ranges' property. 78208747Sraj */ 79208747Sraj par_addr_cells = fdt_parent_addr_cells(node); 80208747Sraj if (par_addr_cells > 2) 81208747Sraj return (ERANGE); 82208747Sraj 83208747Sraj len = OF_getproplen(node, "ranges"); 84208747Sraj if (len > sizeof(ranges)) 85208747Sraj return (ENOMEM); 86239274Sgonzo if (len == 0) { 87239274Sgonzo *base = 0; 88239274Sgonzo *size = ULONG_MAX; 89239274Sgonzo return (0); 90239274Sgonzo } 91208747Sraj 92239274Sgonzo if (!(range_id < len)) 93239274Sgonzo return (ERANGE); 94239274Sgonzo 95208747Sraj if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) 96208747Sraj return (EINVAL); 97208747Sraj 98208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 99208747Sraj size_cells); 100208747Sraj tuples = len / tuple_size; 101208747Sraj 102208747Sraj if (fdt_ranges_verify(ranges, tuples, par_addr_cells, 103208747Sraj addr_cells, size_cells)) { 104208747Sraj return (ERANGE); 105208747Sraj } 106239274Sgonzo *base = 0; 107239274Sgonzo *size = 0; 108239274Sgonzo rangesptr = &ranges[range_id]; 109208747Sraj 110239274Sgonzo *base = fdt_data_get((void *)rangesptr, addr_cells); 111208747Sraj rangesptr += addr_cells; 112239274Sgonzo *base += fdt_data_get((void *)rangesptr, par_addr_cells); 113208747Sraj rangesptr += par_addr_cells; 114239274Sgonzo *size = fdt_data_get((void *)rangesptr, size_cells); 115239274Sgonzo return (0); 116239274Sgonzo} 117208747Sraj 118239274Sgonzoint 119239274Sgonzofdt_immr_addr(vm_offset_t immr_va) 120239274Sgonzo{ 121239274Sgonzo phandle_t node; 122239274Sgonzo u_long base, size; 123239274Sgonzo int r; 124208747Sraj 125239274Sgonzo /* 126239274Sgonzo * Try to access the SOC node directly i.e. through /aliases/. 127239274Sgonzo */ 128239274Sgonzo if ((node = OF_finddevice("soc")) != 0) 129239274Sgonzo if (fdt_is_compatible_strict(node, "simple-bus")) 130239274Sgonzo goto moveon; 131239274Sgonzo /* 132239274Sgonzo * Find the node the long way. 133239274Sgonzo */ 134239274Sgonzo if ((node = OF_finddevice("/")) == 0) 135239274Sgonzo return (ENXIO); 136239274Sgonzo 137239274Sgonzo if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) 138239274Sgonzo return (ENXIO); 139239274Sgonzo 140239274Sgonzomoveon: 141239274Sgonzo if ((r = fdt_get_range(node, 0, &base, &size)) == 0) { 142239274Sgonzo fdt_immr_pa = base; 143239274Sgonzo fdt_immr_va = immr_va; 144239274Sgonzo fdt_immr_size = size; 145239274Sgonzo } 146239274Sgonzo 147239274Sgonzo return (r); 148208747Sraj} 149208747Sraj 150208747Sraj/* 151208747Sraj * This routine is an early-usage version of the ofw_bus_is_compatible() when 152208747Sraj * the ofw_bus I/F is not available (like early console routines and similar). 153208747Sraj * Note the buffer has to be on the stack since malloc() is usually not 154208747Sraj * available in such cases either. 155208747Sraj */ 156208747Srajint 157208747Srajfdt_is_compatible(phandle_t node, const char *compatstr) 158208747Sraj{ 159208747Sraj char buf[FDT_COMPAT_LEN]; 160208747Sraj char *compat; 161208747Sraj int len, onelen, l, rv; 162208747Sraj 163208747Sraj if ((len = OF_getproplen(node, "compatible")) <= 0) 164208747Sraj return (0); 165208747Sraj 166208747Sraj compat = (char *)&buf; 167208747Sraj bzero(compat, FDT_COMPAT_LEN); 168208747Sraj 169208747Sraj if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 170208747Sraj return (0); 171208747Sraj 172208747Sraj onelen = strlen(compatstr); 173208747Sraj rv = 0; 174208747Sraj while (len > 0) { 175208747Sraj if (strncasecmp(compat, compatstr, onelen) == 0) { 176208747Sraj /* Found it. */ 177208747Sraj rv = 1; 178208747Sraj break; 179208747Sraj } 180208747Sraj /* Slide to the next sub-string. */ 181208747Sraj l = strlen(compat) + 1; 182208747Sraj compat += l; 183208747Sraj len -= l; 184208747Sraj } 185208747Sraj 186208747Sraj return (rv); 187208747Sraj} 188208747Sraj 189208747Srajint 190208747Srajfdt_is_compatible_strict(phandle_t node, const char *compatible) 191208747Sraj{ 192208747Sraj char compat[FDT_COMPAT_LEN]; 193208747Sraj 194208747Sraj if (OF_getproplen(node, "compatible") <= 0) 195208747Sraj return (0); 196208747Sraj 197208747Sraj if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 198208747Sraj return (0); 199208747Sraj 200208747Sraj if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0) 201208747Sraj /* This fits. */ 202208747Sraj return (1); 203208747Sraj 204208747Sraj return (0); 205208747Sraj} 206208747Sraj 207208747Srajphandle_t 208208747Srajfdt_find_compatible(phandle_t start, const char *compat, int strict) 209208747Sraj{ 210208747Sraj phandle_t child; 211208747Sraj 212208747Sraj /* 213208747Sraj * Traverse all children of 'start' node, and find first with 214208747Sraj * matching 'compatible' property. 215208747Sraj */ 216208747Sraj for (child = OF_child(start); child != 0; child = OF_peer(child)) 217208747Sraj if (fdt_is_compatible(child, compat)) { 218208747Sraj if (strict) 219208747Sraj if (!fdt_is_compatible_strict(child, compat)) 220208747Sraj continue; 221208747Sraj return (child); 222208747Sraj } 223208747Sraj return (0); 224208747Sraj} 225208747Sraj 226266200Sianphandle_t 227266200Sianfdt_depth_search_compatible(phandle_t start, const char *compat, int strict) 228266200Sian{ 229266200Sian phandle_t child, node; 230266200Sian 231266200Sian /* 232266200Sian * Depth-search all descendants of 'start' node, and find first with 233266200Sian * matching 'compatible' property. 234266200Sian */ 235266200Sian for (node = OF_child(start); node != 0; node = OF_peer(node)) { 236266200Sian if (fdt_is_compatible(node, compat) && 237266200Sian (strict == 0 || fdt_is_compatible_strict(node, compat))) { 238266200Sian return (node); 239266200Sian } 240266200Sian child = fdt_depth_search_compatible(node, compat, strict); 241266200Sian if (child != 0) 242266200Sian return (child); 243266200Sian } 244266200Sian return (0); 245266200Sian} 246266200Sian 247208747Srajint 248208747Srajfdt_is_enabled(phandle_t node) 249208747Sraj{ 250208747Sraj char *stat; 251208747Sraj int ena, len; 252208747Sraj 253208747Sraj len = OF_getprop_alloc(node, "status", sizeof(char), 254208747Sraj (void **)&stat); 255208747Sraj 256208747Sraj if (len <= 0) 257208747Sraj /* It is OK if no 'status' property. */ 258208747Sraj return (1); 259208747Sraj 260208747Sraj /* Anything other than 'okay' means disabled. */ 261208747Sraj ena = 0; 262208747Sraj if (strncmp((char *)stat, "okay", len) == 0) 263208747Sraj ena = 1; 264208747Sraj 265208747Sraj free(stat, M_OFWPROP); 266208747Sraj return (ena); 267208747Sraj} 268208747Sraj 269208747Srajint 270208747Srajfdt_is_type(phandle_t node, const char *typestr) 271208747Sraj{ 272208747Sraj char type[FDT_TYPE_LEN]; 273208747Sraj 274208747Sraj if (OF_getproplen(node, "device_type") <= 0) 275208747Sraj return (0); 276208747Sraj 277208747Sraj if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0) 278208747Sraj return (0); 279208747Sraj 280208747Sraj if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0) 281208747Sraj /* This fits. */ 282208747Sraj return (1); 283208747Sraj 284208747Sraj return (0); 285208747Sraj} 286208747Sraj 287208747Srajint 288208747Srajfdt_parent_addr_cells(phandle_t node) 289208747Sraj{ 290208747Sraj pcell_t addr_cells; 291208747Sraj 292208747Sraj /* Find out #address-cells of the superior bus. */ 293208747Sraj if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, 294208747Sraj sizeof(addr_cells)) <= 0) 295208747Sraj addr_cells = 2; 296208747Sraj 297208747Sraj return ((int)fdt32_to_cpu(addr_cells)); 298208747Sraj} 299208747Sraj 300208747Srajint 301208747Srajfdt_data_verify(void *data, int cells) 302208747Sraj{ 303208747Sraj uint64_t d64; 304208747Sraj 305208747Sraj if (cells > 1) { 306208747Sraj d64 = fdt64_to_cpu(*((uint64_t *)data)); 307208747Sraj if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2) 308208747Sraj return (ERANGE); 309208747Sraj } 310208747Sraj 311208747Sraj return (0); 312208747Sraj} 313208747Sraj 314208747Srajint 315208747Srajfdt_pm_is_enabled(phandle_t node) 316208747Sraj{ 317208747Sraj int ret; 318208747Sraj 319208747Sraj ret = 1; 320208747Sraj 321208747Sraj#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 322208747Sraj ret = fdt_pm(node); 323208747Sraj#endif 324208747Sraj return (ret); 325208747Sraj} 326208747Sraj 327208747Sraju_long 328208747Srajfdt_data_get(void *data, int cells) 329208747Sraj{ 330208747Sraj 331208747Sraj if (cells == 1) 332208747Sraj return (fdt32_to_cpu(*((uint32_t *)data))); 333208747Sraj 334208747Sraj return (fdt64_to_cpu(*((uint64_t *)data))); 335208747Sraj} 336208747Sraj 337208747Srajint 338208747Srajfdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) 339208747Sraj{ 340208747Sraj pcell_t cell; 341208747Sraj int cell_size; 342208747Sraj 343208747Sraj /* 344208747Sraj * Retrieve #{address,size}-cells. 345208747Sraj */ 346208747Sraj cell_size = sizeof(cell); 347208747Sraj if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size) 348208747Sraj cell = 2; 349208747Sraj *addr_cells = fdt32_to_cpu((int)cell); 350208747Sraj 351208747Sraj if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size) 352208747Sraj cell = 1; 353208747Sraj *size_cells = fdt32_to_cpu((int)cell); 354208747Sraj 355208747Sraj if (*addr_cells > 3 || *size_cells > 2) 356208747Sraj return (ERANGE); 357208747Sraj return (0); 358208747Sraj} 359208747Sraj 360208747Srajint 361208747Srajfdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells, 362208747Sraj int this_addr_cells, int this_size_cells) 363208747Sraj{ 364208747Sraj int i, rv, ulsz; 365208747Sraj 366208747Sraj if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2) 367208747Sraj return (ERANGE); 368208747Sraj 369208747Sraj /* 370208747Sraj * This is the max size the resource manager can handle for addresses 371208747Sraj * and sizes. 372208747Sraj */ 373208747Sraj ulsz = sizeof(u_long); 374208747Sraj if (par_addr_cells <= ulsz && this_addr_cells <= ulsz && 375208747Sraj this_size_cells <= ulsz) 376208747Sraj /* We can handle everything */ 377208747Sraj return (0); 378208747Sraj 379208747Sraj rv = 0; 380208747Sraj for (i = 0; i < tuples; i++) { 381208747Sraj 382208747Sraj if (fdt_data_verify((void *)ranges, par_addr_cells)) 383208747Sraj goto err; 384208747Sraj ranges += par_addr_cells; 385208747Sraj 386208747Sraj if (fdt_data_verify((void *)ranges, this_addr_cells)) 387208747Sraj goto err; 388208747Sraj ranges += this_addr_cells; 389208747Sraj 390208747Sraj if (fdt_data_verify((void *)ranges, this_size_cells)) 391208747Sraj goto err; 392208747Sraj ranges += this_size_cells; 393208747Sraj } 394208747Sraj 395208747Sraj return (0); 396208747Sraj 397208747Srajerr: 398208747Sraj debugf("using address range >%d-bit not supported\n", ulsz * 8); 399208747Sraj return (ERANGE); 400208747Sraj} 401208747Sraj 402208747Srajint 403208747Srajfdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start, 404208747Sraj u_long *count) 405208747Sraj{ 406208747Sraj 407208747Sraj /* Address portion. */ 408208747Sraj if (fdt_data_verify((void *)data, addr_cells)) 409208747Sraj return (ERANGE); 410208747Sraj 411208747Sraj *start = fdt_data_get((void *)data, addr_cells); 412208747Sraj data += addr_cells; 413208747Sraj 414208747Sraj /* Size portion. */ 415208747Sraj if (fdt_data_verify((void *)data, size_cells)) 416208747Sraj return (ERANGE); 417208747Sraj 418208747Sraj *count = fdt_data_get((void *)data, size_cells); 419208747Sraj return (0); 420208747Sraj} 421208747Sraj 422208747Srajint 423208747Srajfdt_regsize(phandle_t node, u_long *base, u_long *size) 424208747Sraj{ 425208747Sraj pcell_t reg[4]; 426208747Sraj int addr_cells, len, size_cells; 427208747Sraj 428208747Sraj if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells)) 429208747Sraj return (ENXIO); 430208747Sraj 431208747Sraj if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg)) 432208747Sraj return (ENOMEM); 433208747Sraj 434208747Sraj len = OF_getprop(node, "reg", ®, sizeof(reg)); 435208747Sraj if (len <= 0) 436208747Sraj return (EINVAL); 437208747Sraj 438208747Sraj *base = fdt_data_get(®[0], addr_cells); 439208747Sraj *size = fdt_data_get(®[addr_cells], size_cells); 440208747Sraj return (0); 441208747Sraj} 442208747Sraj 443208747Srajint 444239274Sgonzofdt_reg_to_rl(phandle_t node, struct resource_list *rl) 445208747Sraj{ 446248509Sray u_long end, count, start; 447208747Sraj pcell_t *reg, *regptr; 448208747Sraj pcell_t addr_cells, size_cells; 449208747Sraj int tuple_size, tuples; 450208747Sraj int i, rv; 451239274Sgonzo long busaddr, bussize; 452208747Sraj 453208747Sraj if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 454208747Sraj return (ENXIO); 455240484Sgber if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) { 456240484Sgber busaddr = 0; 457240484Sgber bussize = 0; 458240484Sgber } 459208747Sraj 460208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 461208747Sraj tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); 462208747Sraj debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 463208747Sraj debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 464208747Sraj if (tuples <= 0) 465208747Sraj /* No 'reg' property in this node. */ 466208747Sraj return (0); 467208747Sraj 468208747Sraj regptr = reg; 469208747Sraj for (i = 0; i < tuples; i++) { 470208747Sraj 471248509Sray rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, 472248509Sray &count); 473208747Sraj if (rv != 0) { 474208747Sraj resource_list_free(rl); 475208747Sraj goto out; 476208747Sraj } 477208747Sraj reg += addr_cells + size_cells; 478208747Sraj 479208747Sraj /* Calculate address range relative to base. */ 480239274Sgonzo start += busaddr; 481248467Sray end = start + count - 1; 482208747Sraj 483248467Sray debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, 484208747Sraj end, count); 485208747Sraj 486248467Sray resource_list_add(rl, SYS_RES_MEMORY, i, start, end, 487208747Sraj count); 488208747Sraj } 489208747Sraj rv = 0; 490208747Sraj 491208747Srajout: 492208747Sraj free(regptr, M_OFWPROP); 493208747Sraj return (rv); 494208747Sraj} 495208747Sraj 496208747Srajint 497232518Srajfdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) 498208747Sraj{ 499208747Sraj phandle_t phy_node; 500208747Sraj pcell_t phy_handle, phy_reg; 501232518Sraj uint32_t i; 502232518Sraj device_t parent, child; 503208747Sraj 504265967Sian if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 505208747Sraj sizeof(phy_handle)) <= 0) 506208747Sraj return (ENXIO); 507208747Sraj 508273652Sian phy_node = OF_node_from_xref(phy_handle); 509208747Sraj 510208747Sraj if (OF_getprop(phy_node, "reg", (void *)&phy_reg, 511208747Sraj sizeof(phy_reg)) <= 0) 512208747Sraj return (ENXIO); 513208747Sraj 514208747Sraj *phy_addr = fdt32_to_cpu(phy_reg); 515232518Sraj 516232518Sraj /* 517232518Sraj * Search for softc used to communicate with phy. 518232518Sraj */ 519232518Sraj 520232518Sraj /* 521232518Sraj * Step 1: Search for ancestor of the phy-node with a "phy-handle" 522232518Sraj * property set. 523232518Sraj */ 524232518Sraj phy_node = OF_parent(phy_node); 525232518Sraj while (phy_node != 0) { 526232518Sraj if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, 527232518Sraj sizeof(phy_handle)) > 0) 528232518Sraj break; 529232518Sraj phy_node = OF_parent(phy_node); 530232518Sraj } 531232518Sraj if (phy_node == 0) 532232518Sraj return (ENXIO); 533232518Sraj 534232518Sraj /* 535232518Sraj * Step 2: For each device with the same parent and name as ours 536232518Sraj * compare its node with the one found in step 1, ancestor of phy 537232518Sraj * node (stored in phy_node). 538232518Sraj */ 539232518Sraj parent = device_get_parent(dev); 540232518Sraj i = 0; 541232518Sraj child = device_find_child(parent, device_get_name(dev), i); 542232518Sraj while (child != NULL) { 543232518Sraj if (ofw_bus_get_node(child) == phy_node) 544232518Sraj break; 545232518Sraj i++; 546232518Sraj child = device_find_child(parent, device_get_name(dev), i); 547232518Sraj } 548232518Sraj if (child == NULL) 549232518Sraj return (ENXIO); 550232518Sraj 551232518Sraj /* 552232518Sraj * Use softc of the device found. 553232518Sraj */ 554232518Sraj *phy_sc = (void *)device_get_softc(child); 555232518Sraj 556208747Sraj return (0); 557208747Sraj} 558208747Sraj 559208747Srajint 560243690Sgonzofdt_get_reserved_regions(struct mem_region *mr, int *mrcnt) 561243690Sgonzo{ 562243690Sgonzo pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS]; 563243690Sgonzo pcell_t *reservep; 564243690Sgonzo phandle_t memory, root; 565243690Sgonzo uint32_t memory_size; 566243690Sgonzo int addr_cells, size_cells; 567243690Sgonzo int i, max_size, res_len, rv, tuple_size, tuples; 568243690Sgonzo 569243690Sgonzo max_size = sizeof(reserve); 570243690Sgonzo root = OF_finddevice("/"); 571243690Sgonzo memory = OF_finddevice("/memory"); 572243690Sgonzo if (memory == -1) { 573243690Sgonzo rv = ENXIO; 574243690Sgonzo goto out; 575243690Sgonzo } 576243690Sgonzo 577243690Sgonzo if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 578243690Sgonzo &size_cells)) != 0) 579243690Sgonzo goto out; 580243690Sgonzo 581243690Sgonzo if (addr_cells > 2) { 582243690Sgonzo rv = ERANGE; 583243690Sgonzo goto out; 584243690Sgonzo } 585243690Sgonzo 586243690Sgonzo tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 587243690Sgonzo 588243690Sgonzo res_len = OF_getproplen(root, "memreserve"); 589243690Sgonzo if (res_len <= 0 || res_len > sizeof(reserve)) { 590243690Sgonzo rv = ERANGE; 591243690Sgonzo goto out; 592243690Sgonzo } 593243690Sgonzo 594243690Sgonzo if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) { 595243690Sgonzo rv = ENXIO; 596243690Sgonzo goto out; 597243690Sgonzo } 598243690Sgonzo 599243690Sgonzo memory_size = 0; 600243690Sgonzo tuples = res_len / tuple_size; 601243690Sgonzo reservep = (pcell_t *)&reserve; 602243690Sgonzo for (i = 0; i < tuples; i++) { 603243690Sgonzo 604243690Sgonzo rv = fdt_data_to_res(reservep, addr_cells, size_cells, 605243690Sgonzo (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 606243690Sgonzo 607243690Sgonzo if (rv != 0) 608243690Sgonzo goto out; 609243690Sgonzo 610243690Sgonzo reservep += addr_cells + size_cells; 611243690Sgonzo } 612243690Sgonzo 613243690Sgonzo *mrcnt = i; 614243690Sgonzo rv = 0; 615243690Sgonzoout: 616243690Sgonzo return (rv); 617243690Sgonzo} 618243690Sgonzo 619243690Sgonzoint 620208747Srajfdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize) 621208747Sraj{ 622208747Sraj pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; 623208747Sraj pcell_t *regp; 624208747Sraj phandle_t memory; 625208747Sraj uint32_t memory_size; 626208747Sraj int addr_cells, size_cells; 627208747Sraj int i, max_size, reg_len, rv, tuple_size, tuples; 628208747Sraj 629208747Sraj max_size = sizeof(reg); 630208747Sraj memory = OF_finddevice("/memory"); 631228201Sjchandra if (memory == -1) { 632208747Sraj rv = ENXIO; 633208747Sraj goto out; 634208747Sraj } 635208747Sraj 636208747Sraj if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 637208747Sraj &size_cells)) != 0) 638208747Sraj goto out; 639208747Sraj 640208747Sraj if (addr_cells > 2) { 641208747Sraj rv = ERANGE; 642208747Sraj goto out; 643208747Sraj } 644208747Sraj 645208747Sraj tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 646208747Sraj reg_len = OF_getproplen(memory, "reg"); 647208747Sraj if (reg_len <= 0 || reg_len > sizeof(reg)) { 648208747Sraj rv = ERANGE; 649208747Sraj goto out; 650208747Sraj } 651208747Sraj 652208747Sraj if (OF_getprop(memory, "reg", reg, reg_len) <= 0) { 653208747Sraj rv = ENXIO; 654208747Sraj goto out; 655208747Sraj } 656208747Sraj 657208747Sraj memory_size = 0; 658208747Sraj tuples = reg_len / tuple_size; 659208747Sraj regp = (pcell_t *)® 660208747Sraj for (i = 0; i < tuples; i++) { 661208747Sraj 662208747Sraj rv = fdt_data_to_res(regp, addr_cells, size_cells, 663208747Sraj (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 664208747Sraj 665208747Sraj if (rv != 0) 666208747Sraj goto out; 667208747Sraj 668208747Sraj regp += addr_cells + size_cells; 669208747Sraj memory_size += mr[i].mr_size; 670208747Sraj } 671208747Sraj 672208747Sraj if (memory_size == 0) { 673208747Sraj rv = ERANGE; 674208747Sraj goto out; 675208747Sraj } 676208747Sraj 677208747Sraj *mrcnt = i; 678208747Sraj *memsize = memory_size; 679208747Sraj rv = 0; 680208747Srajout: 681208747Sraj return (rv); 682208747Sraj} 683240485Sgber 684240485Sgberint 685240485Sgberfdt_get_unit(device_t dev) 686240485Sgber{ 687240485Sgber const char * name; 688240485Sgber 689240485Sgber name = ofw_bus_get_name(dev); 690240485Sgber name = strchr(name, '@') + 1; 691240485Sgber 692240485Sgber return (strtol(name,NULL,0)); 693240485Sgber} 694