158158742SRafal Jaworowski /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 4d455cc04SAndrew Turner * Copyright (c) 2009-2014 The FreeBSD Foundation 558158742SRafal Jaworowski * 6d455cc04SAndrew Turner * This software was developed by Andrew Turner under sponsorship from 7d455cc04SAndrew Turner * the FreeBSD Foundation. 858158742SRafal Jaworowski * This software was developed by Semihalf under sponsorship from 958158742SRafal Jaworowski * the FreeBSD Foundation. 1058158742SRafal Jaworowski * 1158158742SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 1258158742SRafal Jaworowski * modification, are permitted provided that the following conditions 1358158742SRafal Jaworowski * are met: 1458158742SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 1558158742SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 1658158742SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 1758158742SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 1858158742SRafal Jaworowski * documentation and/or other materials provided with the distribution. 1958158742SRafal Jaworowski * 2058158742SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2158158742SRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2258158742SRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2358158742SRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2458158742SRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2558158742SRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2658158742SRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2758158742SRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2858158742SRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2958158742SRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3058158742SRafal Jaworowski * SUCH DAMAGE. 3158158742SRafal Jaworowski */ 3258158742SRafal Jaworowski 3358158742SRafal Jaworowski #include <sys/param.h> 3458158742SRafal Jaworowski #include <sys/systm.h> 3558158742SRafal Jaworowski #include <sys/kernel.h> 3658158742SRafal Jaworowski #include <sys/module.h> 3758158742SRafal Jaworowski #include <sys/bus.h> 388bb93637SOleksandr Tymoshenko #include <sys/limits.h> 39a183d81dSStephen J. Kiernan #include <sys/sysctl.h> 4058158742SRafal Jaworowski 4158158742SRafal Jaworowski #include <machine/resource.h> 4258158742SRafal Jaworowski 4358158742SRafal Jaworowski #include <dev/fdt/fdt_common.h> 4458158742SRafal Jaworowski #include <dev/ofw/ofw_bus.h> 4558158742SRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 4658158742SRafal Jaworowski #include <dev/ofw/openfirm.h> 4758158742SRafal Jaworowski 4858158742SRafal Jaworowski #include "ofw_bus_if.h" 4958158742SRafal Jaworowski 5058158742SRafal Jaworowski #ifdef DEBUG 5158158742SRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 5258158742SRafal Jaworowski printf(fmt,##args); } while (0) 5358158742SRafal Jaworowski #else 5458158742SRafal Jaworowski #define debugf(fmt, args...) 5558158742SRafal Jaworowski #endif 5658158742SRafal Jaworowski 5758158742SRafal Jaworowski #define FDT_COMPAT_LEN 255 5858158742SRafal Jaworowski 5958158742SRafal Jaworowski #define FDT_REG_CELLS 4 60bfd084c8SMarcin Wojtas #define FDT_RANGES_SIZE 48 6158158742SRafal Jaworowski 627029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, fdt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 637029da5cSPawel Biernacki "Flattened Device Tree"); 64a183d81dSStephen J. Kiernan 651f40dbc8SBrooks Davis struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); 661f40dbc8SBrooks Davis 67d455cc04SAndrew Turner static int 68d455cc04SAndrew Turner fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base, 69d455cc04SAndrew Turner u_long *size) 70d455cc04SAndrew Turner { 71d455cc04SAndrew Turner pcell_t ranges[32], *rangesptr; 72d455cc04SAndrew Turner pcell_t addr_cells, size_cells, par_addr_cells; 73d455cc04SAndrew Turner u_long bus_addr, par_bus_addr, pbase, psize; 74d455cc04SAndrew Turner int err, i, len, tuple_size, tuples; 75d455cc04SAndrew Turner 7630ef1a05SAndrew Turner if (node == 0) { 7730ef1a05SAndrew Turner *base = 0; 7830ef1a05SAndrew Turner *size = ULONG_MAX; 7930ef1a05SAndrew Turner return (0); 8030ef1a05SAndrew Turner } 8130ef1a05SAndrew Turner 82d455cc04SAndrew Turner if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 83d455cc04SAndrew Turner return (ENXIO); 84d455cc04SAndrew Turner /* 85d455cc04SAndrew Turner * Process 'ranges' property. 86d455cc04SAndrew Turner */ 87d455cc04SAndrew Turner par_addr_cells = fdt_parent_addr_cells(node); 88d455cc04SAndrew Turner if (par_addr_cells > 2) { 89d455cc04SAndrew Turner return (ERANGE); 90d455cc04SAndrew Turner } 91d455cc04SAndrew Turner 92d455cc04SAndrew Turner len = OF_getproplen(node, "ranges"); 93d455cc04SAndrew Turner if (len < 0) 94d455cc04SAndrew Turner return (-1); 95d455cc04SAndrew Turner if (len > sizeof(ranges)) 96d455cc04SAndrew Turner return (ENOMEM); 97d455cc04SAndrew Turner if (len == 0) { 9830ef1a05SAndrew Turner return (fdt_get_range_by_busaddr(OF_parent(node), addr, 9930ef1a05SAndrew Turner base, size)); 100d455cc04SAndrew Turner } 101d455cc04SAndrew Turner 102d455cc04SAndrew Turner if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) 103d455cc04SAndrew Turner return (EINVAL); 104d455cc04SAndrew Turner 105d455cc04SAndrew Turner tuple_size = addr_cells + par_addr_cells + size_cells; 106d455cc04SAndrew Turner tuples = len / (tuple_size * sizeof(cell_t)); 107d455cc04SAndrew Turner 108ba2ea14aSRuslan Bukin if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) 109d455cc04SAndrew Turner return (ERANGE); 110ba2ea14aSRuslan Bukin 111d455cc04SAndrew Turner *base = 0; 112d455cc04SAndrew Turner *size = 0; 113d455cc04SAndrew Turner 114d455cc04SAndrew Turner for (i = 0; i < tuples; i++) { 115d455cc04SAndrew Turner rangesptr = &ranges[i * tuple_size]; 116d455cc04SAndrew Turner 117d455cc04SAndrew Turner bus_addr = fdt_data_get((void *)rangesptr, addr_cells); 118d455cc04SAndrew Turner if (bus_addr != addr) 119d455cc04SAndrew Turner continue; 120d455cc04SAndrew Turner rangesptr += addr_cells; 121d455cc04SAndrew Turner 122d455cc04SAndrew Turner par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells); 123d455cc04SAndrew Turner rangesptr += par_addr_cells; 124d455cc04SAndrew Turner 125d455cc04SAndrew Turner err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr, 126d455cc04SAndrew Turner &pbase, &psize); 127d455cc04SAndrew Turner if (err > 0) 128d455cc04SAndrew Turner return (err); 129d455cc04SAndrew Turner if (err == 0) 130d455cc04SAndrew Turner *base = pbase; 131d455cc04SAndrew Turner else 132d455cc04SAndrew Turner *base = par_bus_addr; 133d455cc04SAndrew Turner 134d455cc04SAndrew Turner *size = fdt_data_get((void *)rangesptr, size_cells); 135d455cc04SAndrew Turner 136d455cc04SAndrew Turner return (0); 137d455cc04SAndrew Turner } 138d455cc04SAndrew Turner 139d455cc04SAndrew Turner return (EINVAL); 140d455cc04SAndrew Turner } 141d455cc04SAndrew Turner 14258158742SRafal Jaworowski int 1438bb93637SOleksandr Tymoshenko fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) 14458158742SRafal Jaworowski { 145bfd084c8SMarcin Wojtas pcell_t ranges[FDT_RANGES_SIZE], *rangesptr; 14658158742SRafal Jaworowski pcell_t addr_cells, size_cells, par_addr_cells; 147d455cc04SAndrew Turner u_long par_bus_addr, pbase, psize; 148151ba793SAlexander Kabaev int err, len; 14958158742SRafal Jaworowski 15058158742SRafal Jaworowski if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 15158158742SRafal Jaworowski return (ENXIO); 15258158742SRafal Jaworowski /* 15358158742SRafal Jaworowski * Process 'ranges' property. 15458158742SRafal Jaworowski */ 15558158742SRafal Jaworowski par_addr_cells = fdt_parent_addr_cells(node); 15658158742SRafal Jaworowski if (par_addr_cells > 2) 15758158742SRafal Jaworowski return (ERANGE); 15858158742SRafal Jaworowski 15958158742SRafal Jaworowski len = OF_getproplen(node, "ranges"); 16058158742SRafal Jaworowski if (len > sizeof(ranges)) 16158158742SRafal Jaworowski return (ENOMEM); 1628bb93637SOleksandr Tymoshenko if (len == 0) { 1638bb93637SOleksandr Tymoshenko *base = 0; 1648bb93637SOleksandr Tymoshenko *size = ULONG_MAX; 1658bb93637SOleksandr Tymoshenko return (0); 1668bb93637SOleksandr Tymoshenko } 1678bb93637SOleksandr Tymoshenko 1688bb93637SOleksandr Tymoshenko if (!(range_id < len)) 1698bb93637SOleksandr Tymoshenko return (ERANGE); 17058158742SRafal Jaworowski 17158158742SRafal Jaworowski if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) 17258158742SRafal Jaworowski return (EINVAL); 17358158742SRafal Jaworowski 174ba2ea14aSRuslan Bukin if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) 17558158742SRafal Jaworowski return (ERANGE); 176ba2ea14aSRuslan Bukin 1778bb93637SOleksandr Tymoshenko *base = 0; 1788bb93637SOleksandr Tymoshenko *size = 0; 1798bb93637SOleksandr Tymoshenko rangesptr = &ranges[range_id]; 18058158742SRafal Jaworowski 1818bb93637SOleksandr Tymoshenko *base = fdt_data_get((void *)rangesptr, addr_cells); 18258158742SRafal Jaworowski rangesptr += addr_cells; 183d455cc04SAndrew Turner 184d455cc04SAndrew Turner par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells); 18558158742SRafal Jaworowski rangesptr += par_addr_cells; 186d455cc04SAndrew Turner 187d455cc04SAndrew Turner err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr, 188d455cc04SAndrew Turner &pbase, &psize); 189d455cc04SAndrew Turner if (err == 0) 190d455cc04SAndrew Turner *base += pbase; 191d455cc04SAndrew Turner else 192d455cc04SAndrew Turner *base += par_bus_addr; 193d455cc04SAndrew Turner 1948bb93637SOleksandr Tymoshenko *size = fdt_data_get((void *)rangesptr, size_cells); 1958bb93637SOleksandr Tymoshenko return (0); 1968bb93637SOleksandr Tymoshenko } 19758158742SRafal Jaworowski 1988bb93637SOleksandr Tymoshenko int 19958158742SRafal Jaworowski fdt_is_compatible_strict(phandle_t node, const char *compatible) 20058158742SRafal Jaworowski { 20158158742SRafal Jaworowski char compat[FDT_COMPAT_LEN]; 20258158742SRafal Jaworowski 20358158742SRafal Jaworowski if (OF_getproplen(node, "compatible") <= 0) 20458158742SRafal Jaworowski return (0); 20558158742SRafal Jaworowski 20658158742SRafal Jaworowski if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 20758158742SRafal Jaworowski return (0); 20858158742SRafal Jaworowski 20958158742SRafal Jaworowski if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0) 21058158742SRafal Jaworowski /* This fits. */ 21158158742SRafal Jaworowski return (1); 21258158742SRafal Jaworowski 21358158742SRafal Jaworowski return (0); 21458158742SRafal Jaworowski } 21558158742SRafal Jaworowski 21658158742SRafal Jaworowski phandle_t 21758158742SRafal Jaworowski fdt_find_compatible(phandle_t start, const char *compat, int strict) 21858158742SRafal Jaworowski { 21958158742SRafal Jaworowski phandle_t child; 22058158742SRafal Jaworowski 22158158742SRafal Jaworowski /* 22258158742SRafal Jaworowski * Traverse all children of 'start' node, and find first with 22358158742SRafal Jaworowski * matching 'compatible' property. 22458158742SRafal Jaworowski */ 22558158742SRafal Jaworowski for (child = OF_child(start); child != 0; child = OF_peer(child)) 2269d9889b5SAndrew Turner if (ofw_bus_node_is_compatible(child, compat)) { 22758158742SRafal Jaworowski if (strict) 22858158742SRafal Jaworowski if (!fdt_is_compatible_strict(child, compat)) 22958158742SRafal Jaworowski continue; 23058158742SRafal Jaworowski return (child); 23158158742SRafal Jaworowski } 23258158742SRafal Jaworowski return (0); 23358158742SRafal Jaworowski } 23458158742SRafal Jaworowski 235731ff010SIan Lepore phandle_t 236731ff010SIan Lepore fdt_depth_search_compatible(phandle_t start, const char *compat, int strict) 237731ff010SIan Lepore { 238731ff010SIan Lepore phandle_t child, node; 239731ff010SIan Lepore 240731ff010SIan Lepore /* 241731ff010SIan Lepore * Depth-search all descendants of 'start' node, and find first with 242731ff010SIan Lepore * matching 'compatible' property. 243731ff010SIan Lepore */ 244731ff010SIan Lepore for (node = OF_child(start); node != 0; node = OF_peer(node)) { 2459d9889b5SAndrew Turner if (ofw_bus_node_is_compatible(node, compat) && 246731ff010SIan Lepore (strict == 0 || fdt_is_compatible_strict(node, compat))) { 247731ff010SIan Lepore return (node); 248731ff010SIan Lepore } 249a41679c9SIan Lepore child = fdt_depth_search_compatible(node, compat, strict); 250731ff010SIan Lepore if (child != 0) 251731ff010SIan Lepore return (child); 252731ff010SIan Lepore } 253731ff010SIan Lepore return (0); 254731ff010SIan Lepore } 255731ff010SIan Lepore 25658158742SRafal Jaworowski int 25758158742SRafal Jaworowski fdt_parent_addr_cells(phandle_t node) 25858158742SRafal Jaworowski { 25958158742SRafal Jaworowski pcell_t addr_cells; 26058158742SRafal Jaworowski 26158158742SRafal Jaworowski /* Find out #address-cells of the superior bus. */ 26258158742SRafal Jaworowski if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, 26358158742SRafal Jaworowski sizeof(addr_cells)) <= 0) 264d455cc04SAndrew Turner return (2); 26558158742SRafal Jaworowski 26658158742SRafal Jaworowski return ((int)fdt32_to_cpu(addr_cells)); 26758158742SRafal Jaworowski } 26858158742SRafal Jaworowski 26958158742SRafal Jaworowski u_long 270*a2aff11aSAndrew Turner fdt_data_get(const void *data, int cells) 27158158742SRafal Jaworowski { 27258158742SRafal Jaworowski 27358158742SRafal Jaworowski if (cells == 1) 274*a2aff11aSAndrew Turner return (fdt32_to_cpu(*((const uint32_t *)data))); 27558158742SRafal Jaworowski 276*a2aff11aSAndrew Turner return (fdt64_to_cpu(*((const uint64_t *)data))); 27758158742SRafal Jaworowski } 27858158742SRafal Jaworowski 27958158742SRafal Jaworowski int 28058158742SRafal Jaworowski fdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) 28158158742SRafal Jaworowski { 28258158742SRafal Jaworowski pcell_t cell; 28358158742SRafal Jaworowski int cell_size; 28458158742SRafal Jaworowski 28558158742SRafal Jaworowski /* 28658158742SRafal Jaworowski * Retrieve #{address,size}-cells. 28758158742SRafal Jaworowski */ 28858158742SRafal Jaworowski cell_size = sizeof(cell); 289c6c4276bSAndrew Turner if (OF_getencprop(node, "#address-cells", &cell, cell_size) < cell_size) 290948dad6aSLuiz Otavio O Souza cell = 2; 291c6c4276bSAndrew Turner *addr_cells = (int)cell; 29258158742SRafal Jaworowski 293c6c4276bSAndrew Turner if (OF_getencprop(node, "#size-cells", &cell, cell_size) < cell_size) 29458158742SRafal Jaworowski cell = 1; 295c6c4276bSAndrew Turner *size_cells = (int)cell; 29658158742SRafal Jaworowski 29758158742SRafal Jaworowski if (*addr_cells > 3 || *size_cells > 2) 29858158742SRafal Jaworowski return (ERANGE); 29958158742SRafal Jaworowski return (0); 30058158742SRafal Jaworowski } 30158158742SRafal Jaworowski 30258158742SRafal Jaworowski int 303*a2aff11aSAndrew Turner fdt_data_to_res(const pcell_t *data, int addr_cells, int size_cells, 304*a2aff11aSAndrew Turner u_long *start, u_long *count) 30558158742SRafal Jaworowski { 30658158742SRafal Jaworowski 30758158742SRafal Jaworowski /* Address portion. */ 308ba2ea14aSRuslan Bukin if (addr_cells > 2) 30958158742SRafal Jaworowski return (ERANGE); 31058158742SRafal Jaworowski 311*a2aff11aSAndrew Turner *start = fdt_data_get((const void *)data, addr_cells); 31258158742SRafal Jaworowski data += addr_cells; 31358158742SRafal Jaworowski 31458158742SRafal Jaworowski /* Size portion. */ 315ba2ea14aSRuslan Bukin if (size_cells > 2) 31658158742SRafal Jaworowski return (ERANGE); 31758158742SRafal Jaworowski 318*a2aff11aSAndrew Turner *count = fdt_data_get((const void *)data, size_cells); 31958158742SRafal Jaworowski return (0); 32058158742SRafal Jaworowski } 32158158742SRafal Jaworowski 32258158742SRafal Jaworowski int 32358158742SRafal Jaworowski fdt_regsize(phandle_t node, u_long *base, u_long *size) 32458158742SRafal Jaworowski { 32558158742SRafal Jaworowski pcell_t reg[4]; 32658158742SRafal Jaworowski int addr_cells, len, size_cells; 32758158742SRafal Jaworowski 32858158742SRafal Jaworowski if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells)) 32958158742SRafal Jaworowski return (ENXIO); 33058158742SRafal Jaworowski 33158158742SRafal Jaworowski if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg)) 33258158742SRafal Jaworowski return (ENOMEM); 33358158742SRafal Jaworowski 33458158742SRafal Jaworowski len = OF_getprop(node, "reg", ®, sizeof(reg)); 33558158742SRafal Jaworowski if (len <= 0) 33658158742SRafal Jaworowski return (EINVAL); 33758158742SRafal Jaworowski 33858158742SRafal Jaworowski *base = fdt_data_get(®[0], addr_cells); 33958158742SRafal Jaworowski *size = fdt_data_get(®[addr_cells], size_cells); 34058158742SRafal Jaworowski return (0); 34158158742SRafal Jaworowski } 34258158742SRafal Jaworowski 34358158742SRafal Jaworowski int 344aa15e881SRafal Jaworowski fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) 34558158742SRafal Jaworowski { 34658158742SRafal Jaworowski phandle_t phy_node; 34758158742SRafal Jaworowski pcell_t phy_handle, phy_reg; 348aa15e881SRafal Jaworowski uint32_t i; 349aa15e881SRafal Jaworowski device_t parent, child; 35058158742SRafal Jaworowski 351755c9591SNathan Whitehorn if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 35258158742SRafal Jaworowski sizeof(phy_handle)) <= 0) 35358158742SRafal Jaworowski return (ENXIO); 35458158742SRafal Jaworowski 355752ba930SIan Lepore phy_node = OF_node_from_xref(phy_handle); 35658158742SRafal Jaworowski 357c6c4276bSAndrew Turner if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, 35858158742SRafal Jaworowski sizeof(phy_reg)) <= 0) 35958158742SRafal Jaworowski return (ENXIO); 36058158742SRafal Jaworowski 361c6c4276bSAndrew Turner *phy_addr = phy_reg; 362aa15e881SRafal Jaworowski 3635eb26411SEd Maste if (phy_sc == NULL) 3645eb26411SEd Maste return (0); 3655eb26411SEd Maste 366aa15e881SRafal Jaworowski /* 367aa15e881SRafal Jaworowski * Search for softc used to communicate with phy. 368aa15e881SRafal Jaworowski */ 369aa15e881SRafal Jaworowski 370aa15e881SRafal Jaworowski /* 371aa15e881SRafal Jaworowski * Step 1: Search for ancestor of the phy-node with a "phy-handle" 372aa15e881SRafal Jaworowski * property set. 373aa15e881SRafal Jaworowski */ 374aa15e881SRafal Jaworowski phy_node = OF_parent(phy_node); 375aa15e881SRafal Jaworowski while (phy_node != 0) { 376aa15e881SRafal Jaworowski if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, 377aa15e881SRafal Jaworowski sizeof(phy_handle)) > 0) 378aa15e881SRafal Jaworowski break; 379aa15e881SRafal Jaworowski phy_node = OF_parent(phy_node); 380aa15e881SRafal Jaworowski } 381aa15e881SRafal Jaworowski if (phy_node == 0) 382aa15e881SRafal Jaworowski return (ENXIO); 383aa15e881SRafal Jaworowski 384aa15e881SRafal Jaworowski /* 385aa15e881SRafal Jaworowski * Step 2: For each device with the same parent and name as ours 386aa15e881SRafal Jaworowski * compare its node with the one found in step 1, ancestor of phy 387aa15e881SRafal Jaworowski * node (stored in phy_node). 388aa15e881SRafal Jaworowski */ 389aa15e881SRafal Jaworowski parent = device_get_parent(dev); 390aa15e881SRafal Jaworowski i = 0; 391aa15e881SRafal Jaworowski child = device_find_child(parent, device_get_name(dev), i); 392aa15e881SRafal Jaworowski while (child != NULL) { 393aa15e881SRafal Jaworowski if (ofw_bus_get_node(child) == phy_node) 394aa15e881SRafal Jaworowski break; 395aa15e881SRafal Jaworowski i++; 396aa15e881SRafal Jaworowski child = device_find_child(parent, device_get_name(dev), i); 397aa15e881SRafal Jaworowski } 398aa15e881SRafal Jaworowski if (child == NULL) 399aa15e881SRafal Jaworowski return (ENXIO); 400aa15e881SRafal Jaworowski 401aa15e881SRafal Jaworowski /* 402aa15e881SRafal Jaworowski * Use softc of the device found. 403aa15e881SRafal Jaworowski */ 404aa15e881SRafal Jaworowski *phy_sc = (void *)device_get_softc(child); 405aa15e881SRafal Jaworowski 40658158742SRafal Jaworowski return (0); 40758158742SRafal Jaworowski } 40858158742SRafal Jaworowski 40958158742SRafal Jaworowski int 41028bc1919SAndrew Turner fdt_foreach_reserved_region(fdt_mem_region_cb cb, void *arg) 41128bc1919SAndrew Turner { 41228bc1919SAndrew Turner struct mem_region mr; 41328bc1919SAndrew Turner pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS]; 41428bc1919SAndrew Turner pcell_t *reservep; 41528bc1919SAndrew Turner phandle_t memory, root; 41628bc1919SAndrew Turner int addr_cells, size_cells; 41728bc1919SAndrew Turner int i, res_len, rv, tuple_size, tuples; 41828bc1919SAndrew Turner 41928bc1919SAndrew Turner root = OF_finddevice("/"); 42028bc1919SAndrew Turner memory = OF_finddevice("/memory"); 42128bc1919SAndrew Turner if (memory == -1) 42228bc1919SAndrew Turner return (ENXIO); 42328bc1919SAndrew Turner 42428bc1919SAndrew Turner if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 42528bc1919SAndrew Turner &size_cells)) != 0) 42628bc1919SAndrew Turner return (rv); 42728bc1919SAndrew Turner 42828bc1919SAndrew Turner if (addr_cells > 2) 42928bc1919SAndrew Turner return (ERANGE); 43028bc1919SAndrew Turner 43128bc1919SAndrew Turner tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 43228bc1919SAndrew Turner 43328bc1919SAndrew Turner res_len = OF_getproplen(root, "memreserve"); 43428bc1919SAndrew Turner if (res_len <= 0 || res_len > sizeof(reserve)) 43528bc1919SAndrew Turner return (ERANGE); 43628bc1919SAndrew Turner 43728bc1919SAndrew Turner if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) 43828bc1919SAndrew Turner return (ENXIO); 43928bc1919SAndrew Turner 44028bc1919SAndrew Turner tuples = res_len / tuple_size; 44128bc1919SAndrew Turner reservep = (pcell_t *)&reserve; 44228bc1919SAndrew Turner for (i = 0; i < tuples; i++) { 44328bc1919SAndrew Turner 44428bc1919SAndrew Turner rv = fdt_data_to_res(reservep, addr_cells, size_cells, 44528bc1919SAndrew Turner (u_long *)&mr.mr_start, (u_long *)&mr.mr_size); 44628bc1919SAndrew Turner 44728bc1919SAndrew Turner if (rv != 0) 44828bc1919SAndrew Turner return (rv); 44928bc1919SAndrew Turner 45028bc1919SAndrew Turner cb(&mr, arg); 45128bc1919SAndrew Turner 45228bc1919SAndrew Turner reservep += addr_cells + size_cells; 45328bc1919SAndrew Turner } 45428bc1919SAndrew Turner 45528bc1919SAndrew Turner return (0); 45628bc1919SAndrew Turner } 45728bc1919SAndrew Turner 45828bc1919SAndrew Turner int 4598d5b63efSAndrew Turner fdt_foreach_reserved_mem(fdt_mem_region_cb cb, void *arg) 4608d5b63efSAndrew Turner { 4618d5b63efSAndrew Turner struct mem_region mr; 4628d5b63efSAndrew Turner pcell_t reg[FDT_REG_CELLS]; 4638d5b63efSAndrew Turner phandle_t child, root; 4648d5b63efSAndrew Turner int addr_cells, size_cells; 4658d5b63efSAndrew Turner int rv; 4668d5b63efSAndrew Turner 4678d5b63efSAndrew Turner root = OF_finddevice("/reserved-memory"); 4688d5b63efSAndrew Turner if (root == -1) 4698d5b63efSAndrew Turner return (ENXIO); 4708d5b63efSAndrew Turner 4718d5b63efSAndrew Turner if ((rv = fdt_addrsize_cells(root, &addr_cells, &size_cells)) != 0) 4728d5b63efSAndrew Turner return (rv); 4738d5b63efSAndrew Turner 4748d5b63efSAndrew Turner if (addr_cells + size_cells > FDT_REG_CELLS) 4758d5b63efSAndrew Turner panic("Too many address and size cells %d %d", addr_cells, 4768d5b63efSAndrew Turner size_cells); 4778d5b63efSAndrew Turner 4788d5b63efSAndrew Turner for (child = OF_child(root); child != 0; child = OF_peer(child)) { 4798d5b63efSAndrew Turner if (!OF_hasprop(child, "no-map")) 4808d5b63efSAndrew Turner continue; 4818d5b63efSAndrew Turner 4828d5b63efSAndrew Turner rv = OF_getprop(child, "reg", reg, sizeof(reg)); 4838d5b63efSAndrew Turner if (rv <= 0) 4848d5b63efSAndrew Turner /* XXX: Does a no-map of a dynamic range make sense? */ 4858d5b63efSAndrew Turner continue; 4868d5b63efSAndrew Turner 4878d5b63efSAndrew Turner fdt_data_to_res(reg, addr_cells, size_cells, 4888d5b63efSAndrew Turner (u_long *)&mr.mr_start, (u_long *)&mr.mr_size); 4898d5b63efSAndrew Turner 4908d5b63efSAndrew Turner cb(&mr, arg); 4918d5b63efSAndrew Turner } 4928d5b63efSAndrew Turner 4938d5b63efSAndrew Turner return (0); 4948d5b63efSAndrew Turner } 4958d5b63efSAndrew Turner 4968d5b63efSAndrew Turner int 4970593e411SAndrew Turner fdt_foreach_mem_region(fdt_mem_region_cb cb, void *arg) 4980593e411SAndrew Turner { 4990593e411SAndrew Turner struct mem_region mr; 5000593e411SAndrew Turner pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; 5010593e411SAndrew Turner pcell_t *regp; 5020593e411SAndrew Turner phandle_t memory; 5030593e411SAndrew Turner int addr_cells, size_cells; 5040593e411SAndrew Turner int i, reg_len, rv, tuple_size, tuples; 5050593e411SAndrew Turner 5060593e411SAndrew Turner memory = OF_finddevice("/memory"); 5070593e411SAndrew Turner if (memory == -1) 5080593e411SAndrew Turner return (ENXIO); 5090593e411SAndrew Turner 5100593e411SAndrew Turner if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 5110593e411SAndrew Turner &size_cells)) != 0) 5120593e411SAndrew Turner return (rv); 5130593e411SAndrew Turner 5140593e411SAndrew Turner if (addr_cells > 2) 5150593e411SAndrew Turner return (ERANGE); 5160593e411SAndrew Turner 5170593e411SAndrew Turner tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 5180593e411SAndrew Turner reg_len = OF_getproplen(memory, "reg"); 5190593e411SAndrew Turner if (reg_len <= 0 || reg_len > sizeof(reg)) 5200593e411SAndrew Turner return (ERANGE); 5210593e411SAndrew Turner 5220593e411SAndrew Turner if (OF_getprop(memory, "reg", reg, reg_len) <= 0) 5230593e411SAndrew Turner return (ENXIO); 5240593e411SAndrew Turner 5250593e411SAndrew Turner tuples = reg_len / tuple_size; 5260593e411SAndrew Turner regp = (pcell_t *)® 5270593e411SAndrew Turner for (i = 0; i < tuples; i++) { 5280593e411SAndrew Turner 5290593e411SAndrew Turner rv = fdt_data_to_res(regp, addr_cells, size_cells, 5300593e411SAndrew Turner (u_long *)&mr.mr_start, (u_long *)&mr.mr_size); 5310593e411SAndrew Turner 5320593e411SAndrew Turner if (rv != 0) 5330593e411SAndrew Turner return (rv); 5340593e411SAndrew Turner 5350593e411SAndrew Turner cb(&mr, arg); 5360593e411SAndrew Turner 5370593e411SAndrew Turner regp += addr_cells + size_cells; 5380593e411SAndrew Turner } 5390593e411SAndrew Turner 5400593e411SAndrew Turner return (0); 5410593e411SAndrew Turner } 5420593e411SAndrew Turner 5430593e411SAndrew Turner int 544e64c3743SMichal Meloun fdt_get_chosen_bootargs(char *bootargs, size_t max_size) 545e64c3743SMichal Meloun { 546e64c3743SMichal Meloun phandle_t chosen; 547e64c3743SMichal Meloun 548e64c3743SMichal Meloun chosen = OF_finddevice("/chosen"); 549e64c3743SMichal Meloun if (chosen == -1) 550e64c3743SMichal Meloun return (ENXIO); 551e64c3743SMichal Meloun if (OF_getprop(chosen, "bootargs", bootargs, max_size) == -1) 552e64c3743SMichal Meloun return (ENXIO); 553e64c3743SMichal Meloun return (0); 554e64c3743SMichal Meloun } 555