158158742SRafal Jaworowski /*- 258158742SRafal Jaworowski * Copyright (c) 2009-2010 The FreeBSD Foundation 358158742SRafal Jaworowski * All rights reserved. 458158742SRafal Jaworowski * 558158742SRafal Jaworowski * This software was developed by Semihalf under sponsorship from 658158742SRafal Jaworowski * the FreeBSD Foundation. 758158742SRafal Jaworowski * 858158742SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 958158742SRafal Jaworowski * modification, are permitted provided that the following conditions 1058158742SRafal Jaworowski * are met: 1158158742SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 1258158742SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 1358158742SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 1458158742SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 1558158742SRafal Jaworowski * documentation and/or other materials provided with the distribution. 1658158742SRafal Jaworowski * 1758158742SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1858158742SRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1958158742SRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2058158742SRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2158158742SRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2258158742SRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2358158742SRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2458158742SRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2558158742SRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2658158742SRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2758158742SRafal Jaworowski * SUCH DAMAGE. 2858158742SRafal Jaworowski */ 2958158742SRafal Jaworowski 3058158742SRafal Jaworowski #include <sys/cdefs.h> 3158158742SRafal Jaworowski __FBSDID("$FreeBSD$"); 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> 3958158742SRafal Jaworowski 4058158742SRafal Jaworowski #include <machine/resource.h> 4158158742SRafal Jaworowski 4258158742SRafal Jaworowski #include <dev/fdt/fdt_common.h> 4358158742SRafal Jaworowski #include <dev/ofw/ofw_bus.h> 4458158742SRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 4558158742SRafal Jaworowski #include <dev/ofw/openfirm.h> 4658158742SRafal Jaworowski 4758158742SRafal Jaworowski #include "ofw_bus_if.h" 4858158742SRafal Jaworowski 4958158742SRafal Jaworowski #ifdef DEBUG 5058158742SRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 5158158742SRafal Jaworowski printf(fmt,##args); } while (0) 5258158742SRafal Jaworowski #else 5358158742SRafal Jaworowski #define debugf(fmt, args...) 5458158742SRafal Jaworowski #endif 5558158742SRafal Jaworowski 5658158742SRafal Jaworowski #define FDT_COMPAT_LEN 255 5758158742SRafal Jaworowski #define FDT_TYPE_LEN 64 5858158742SRafal Jaworowski 5958158742SRafal Jaworowski #define FDT_REG_CELLS 4 6058158742SRafal Jaworowski 6158158742SRafal Jaworowski vm_paddr_t fdt_immr_pa; 6258158742SRafal Jaworowski vm_offset_t fdt_immr_va; 6358158742SRafal Jaworowski vm_offset_t fdt_immr_size; 6458158742SRafal Jaworowski 651f40dbc8SBrooks Davis struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); 661f40dbc8SBrooks Davis 6758158742SRafal Jaworowski int 688bb93637SOleksandr Tymoshenko fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) 6958158742SRafal Jaworowski { 7058158742SRafal Jaworowski pcell_t ranges[6], *rangesptr; 7158158742SRafal Jaworowski pcell_t addr_cells, size_cells, par_addr_cells; 7258158742SRafal Jaworowski int len, tuple_size, tuples; 7358158742SRafal Jaworowski 7458158742SRafal Jaworowski if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 7558158742SRafal Jaworowski return (ENXIO); 7658158742SRafal Jaworowski /* 7758158742SRafal Jaworowski * Process 'ranges' property. 7858158742SRafal Jaworowski */ 7958158742SRafal Jaworowski par_addr_cells = fdt_parent_addr_cells(node); 8058158742SRafal Jaworowski if (par_addr_cells > 2) 8158158742SRafal Jaworowski return (ERANGE); 8258158742SRafal Jaworowski 8358158742SRafal Jaworowski len = OF_getproplen(node, "ranges"); 8458158742SRafal Jaworowski if (len > sizeof(ranges)) 8558158742SRafal Jaworowski return (ENOMEM); 868bb93637SOleksandr Tymoshenko if (len == 0) { 878bb93637SOleksandr Tymoshenko *base = 0; 888bb93637SOleksandr Tymoshenko *size = ULONG_MAX; 898bb93637SOleksandr Tymoshenko return (0); 908bb93637SOleksandr Tymoshenko } 918bb93637SOleksandr Tymoshenko 928bb93637SOleksandr Tymoshenko if (!(range_id < len)) 938bb93637SOleksandr Tymoshenko return (ERANGE); 9458158742SRafal Jaworowski 9558158742SRafal Jaworowski if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0) 9658158742SRafal Jaworowski return (EINVAL); 9758158742SRafal Jaworowski 9858158742SRafal Jaworowski tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 9958158742SRafal Jaworowski size_cells); 10058158742SRafal Jaworowski tuples = len / tuple_size; 10158158742SRafal Jaworowski 10258158742SRafal Jaworowski if (fdt_ranges_verify(ranges, tuples, par_addr_cells, 10358158742SRafal Jaworowski addr_cells, size_cells)) { 10458158742SRafal Jaworowski return (ERANGE); 10558158742SRafal Jaworowski } 1068bb93637SOleksandr Tymoshenko *base = 0; 1078bb93637SOleksandr Tymoshenko *size = 0; 1088bb93637SOleksandr Tymoshenko rangesptr = &ranges[range_id]; 10958158742SRafal Jaworowski 1108bb93637SOleksandr Tymoshenko *base = fdt_data_get((void *)rangesptr, addr_cells); 11158158742SRafal Jaworowski rangesptr += addr_cells; 1128bb93637SOleksandr Tymoshenko *base += fdt_data_get((void *)rangesptr, par_addr_cells); 11358158742SRafal Jaworowski rangesptr += par_addr_cells; 1148bb93637SOleksandr Tymoshenko *size = fdt_data_get((void *)rangesptr, size_cells); 1158bb93637SOleksandr Tymoshenko return (0); 1168bb93637SOleksandr Tymoshenko } 11758158742SRafal Jaworowski 1188bb93637SOleksandr Tymoshenko int 1198bb93637SOleksandr Tymoshenko fdt_immr_addr(vm_offset_t immr_va) 1208bb93637SOleksandr Tymoshenko { 1218bb93637SOleksandr Tymoshenko phandle_t node; 1228bb93637SOleksandr Tymoshenko u_long base, size; 1238bb93637SOleksandr Tymoshenko int r; 1248bb93637SOleksandr Tymoshenko 1258bb93637SOleksandr Tymoshenko /* 1268bb93637SOleksandr Tymoshenko * Try to access the SOC node directly i.e. through /aliases/. 1278bb93637SOleksandr Tymoshenko */ 1288bb93637SOleksandr Tymoshenko if ((node = OF_finddevice("soc")) != 0) 1298bb93637SOleksandr Tymoshenko if (fdt_is_compatible_strict(node, "simple-bus")) 1308bb93637SOleksandr Tymoshenko goto moveon; 1318bb93637SOleksandr Tymoshenko /* 1328bb93637SOleksandr Tymoshenko * Find the node the long way. 1338bb93637SOleksandr Tymoshenko */ 1348bb93637SOleksandr Tymoshenko if ((node = OF_finddevice("/")) == 0) 1358bb93637SOleksandr Tymoshenko return (ENXIO); 1368bb93637SOleksandr Tymoshenko 1378bb93637SOleksandr Tymoshenko if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) 1388bb93637SOleksandr Tymoshenko return (ENXIO); 1398bb93637SOleksandr Tymoshenko 1408bb93637SOleksandr Tymoshenko moveon: 1418bb93637SOleksandr Tymoshenko if ((r = fdt_get_range(node, 0, &base, &size)) == 0) { 14258158742SRafal Jaworowski fdt_immr_pa = base; 1434f124b97SRafal Jaworowski fdt_immr_va = immr_va; 14458158742SRafal Jaworowski fdt_immr_size = size; 1458bb93637SOleksandr Tymoshenko } 14658158742SRafal Jaworowski 1478bb93637SOleksandr Tymoshenko return (r); 14858158742SRafal Jaworowski } 14958158742SRafal Jaworowski 15058158742SRafal Jaworowski /* 15158158742SRafal Jaworowski * This routine is an early-usage version of the ofw_bus_is_compatible() when 15258158742SRafal Jaworowski * the ofw_bus I/F is not available (like early console routines and similar). 15358158742SRafal Jaworowski * Note the buffer has to be on the stack since malloc() is usually not 15458158742SRafal Jaworowski * available in such cases either. 15558158742SRafal Jaworowski */ 15658158742SRafal Jaworowski int 15758158742SRafal Jaworowski fdt_is_compatible(phandle_t node, const char *compatstr) 15858158742SRafal Jaworowski { 15958158742SRafal Jaworowski char buf[FDT_COMPAT_LEN]; 16058158742SRafal Jaworowski char *compat; 16158158742SRafal Jaworowski int len, onelen, l, rv; 16258158742SRafal Jaworowski 16358158742SRafal Jaworowski if ((len = OF_getproplen(node, "compatible")) <= 0) 16458158742SRafal Jaworowski return (0); 16558158742SRafal Jaworowski 16658158742SRafal Jaworowski compat = (char *)&buf; 16758158742SRafal Jaworowski bzero(compat, FDT_COMPAT_LEN); 16858158742SRafal Jaworowski 16958158742SRafal Jaworowski if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 17058158742SRafal Jaworowski return (0); 17158158742SRafal Jaworowski 17258158742SRafal Jaworowski onelen = strlen(compatstr); 17358158742SRafal Jaworowski rv = 0; 17458158742SRafal Jaworowski while (len > 0) { 17558158742SRafal Jaworowski if (strncasecmp(compat, compatstr, onelen) == 0) { 17658158742SRafal Jaworowski /* Found it. */ 17758158742SRafal Jaworowski rv = 1; 17858158742SRafal Jaworowski break; 17958158742SRafal Jaworowski } 18058158742SRafal Jaworowski /* Slide to the next sub-string. */ 18158158742SRafal Jaworowski l = strlen(compat) + 1; 18258158742SRafal Jaworowski compat += l; 18358158742SRafal Jaworowski len -= l; 18458158742SRafal Jaworowski } 18558158742SRafal Jaworowski 18658158742SRafal Jaworowski return (rv); 18758158742SRafal Jaworowski } 18858158742SRafal Jaworowski 18958158742SRafal Jaworowski int 19058158742SRafal Jaworowski fdt_is_compatible_strict(phandle_t node, const char *compatible) 19158158742SRafal Jaworowski { 19258158742SRafal Jaworowski char compat[FDT_COMPAT_LEN]; 19358158742SRafal Jaworowski 19458158742SRafal Jaworowski if (OF_getproplen(node, "compatible") <= 0) 19558158742SRafal Jaworowski return (0); 19658158742SRafal Jaworowski 19758158742SRafal Jaworowski if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) 19858158742SRafal Jaworowski return (0); 19958158742SRafal Jaworowski 20058158742SRafal Jaworowski if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0) 20158158742SRafal Jaworowski /* This fits. */ 20258158742SRafal Jaworowski return (1); 20358158742SRafal Jaworowski 20458158742SRafal Jaworowski return (0); 20558158742SRafal Jaworowski } 20658158742SRafal Jaworowski 20758158742SRafal Jaworowski phandle_t 20858158742SRafal Jaworowski fdt_find_compatible(phandle_t start, const char *compat, int strict) 20958158742SRafal Jaworowski { 21058158742SRafal Jaworowski phandle_t child; 21158158742SRafal Jaworowski 21258158742SRafal Jaworowski /* 21358158742SRafal Jaworowski * Traverse all children of 'start' node, and find first with 21458158742SRafal Jaworowski * matching 'compatible' property. 21558158742SRafal Jaworowski */ 21658158742SRafal Jaworowski for (child = OF_child(start); child != 0; child = OF_peer(child)) 21758158742SRafal Jaworowski if (fdt_is_compatible(child, compat)) { 21858158742SRafal Jaworowski if (strict) 21958158742SRafal Jaworowski if (!fdt_is_compatible_strict(child, compat)) 22058158742SRafal Jaworowski continue; 22158158742SRafal Jaworowski return (child); 22258158742SRafal Jaworowski } 22358158742SRafal Jaworowski return (0); 22458158742SRafal Jaworowski } 22558158742SRafal Jaworowski 226731ff010SIan Lepore phandle_t 227731ff010SIan Lepore fdt_depth_search_compatible(phandle_t start, const char *compat, int strict) 228731ff010SIan Lepore { 229731ff010SIan Lepore phandle_t child, node; 230731ff010SIan Lepore 231731ff010SIan Lepore /* 232731ff010SIan Lepore * Depth-search all descendants of 'start' node, and find first with 233731ff010SIan Lepore * matching 'compatible' property. 234731ff010SIan Lepore */ 235731ff010SIan Lepore for (node = OF_child(start); node != 0; node = OF_peer(node)) { 236731ff010SIan Lepore if (fdt_is_compatible(node, compat) && 237731ff010SIan Lepore (strict == 0 || fdt_is_compatible_strict(node, compat))) { 238731ff010SIan Lepore return (node); 239731ff010SIan Lepore } 240a41679c9SIan Lepore child = fdt_depth_search_compatible(node, compat, strict); 241731ff010SIan Lepore if (child != 0) 242731ff010SIan Lepore return (child); 243731ff010SIan Lepore } 244731ff010SIan Lepore return (0); 245731ff010SIan Lepore } 246731ff010SIan Lepore 24758158742SRafal Jaworowski int 24858158742SRafal Jaworowski fdt_is_enabled(phandle_t node) 24958158742SRafal Jaworowski { 25058158742SRafal Jaworowski char *stat; 25158158742SRafal Jaworowski int ena, len; 25258158742SRafal Jaworowski 25358158742SRafal Jaworowski len = OF_getprop_alloc(node, "status", sizeof(char), 25458158742SRafal Jaworowski (void **)&stat); 25558158742SRafal Jaworowski 25658158742SRafal Jaworowski if (len <= 0) 25758158742SRafal Jaworowski /* It is OK if no 'status' property. */ 25858158742SRafal Jaworowski return (1); 25958158742SRafal Jaworowski 26058158742SRafal Jaworowski /* Anything other than 'okay' means disabled. */ 26158158742SRafal Jaworowski ena = 0; 26258158742SRafal Jaworowski if (strncmp((char *)stat, "okay", len) == 0) 26358158742SRafal Jaworowski ena = 1; 26458158742SRafal Jaworowski 26558158742SRafal Jaworowski free(stat, M_OFWPROP); 26658158742SRafal Jaworowski return (ena); 26758158742SRafal Jaworowski } 26858158742SRafal Jaworowski 26958158742SRafal Jaworowski int 27058158742SRafal Jaworowski fdt_is_type(phandle_t node, const char *typestr) 27158158742SRafal Jaworowski { 27258158742SRafal Jaworowski char type[FDT_TYPE_LEN]; 27358158742SRafal Jaworowski 27458158742SRafal Jaworowski if (OF_getproplen(node, "device_type") <= 0) 27558158742SRafal Jaworowski return (0); 27658158742SRafal Jaworowski 27758158742SRafal Jaworowski if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0) 27858158742SRafal Jaworowski return (0); 27958158742SRafal Jaworowski 28058158742SRafal Jaworowski if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0) 28158158742SRafal Jaworowski /* This fits. */ 28258158742SRafal Jaworowski return (1); 28358158742SRafal Jaworowski 28458158742SRafal Jaworowski return (0); 28558158742SRafal Jaworowski } 28658158742SRafal Jaworowski 28758158742SRafal Jaworowski int 28858158742SRafal Jaworowski fdt_parent_addr_cells(phandle_t node) 28958158742SRafal Jaworowski { 29058158742SRafal Jaworowski pcell_t addr_cells; 29158158742SRafal Jaworowski 29258158742SRafal Jaworowski /* Find out #address-cells of the superior bus. */ 29358158742SRafal Jaworowski if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells, 29458158742SRafal Jaworowski sizeof(addr_cells)) <= 0) 29558158742SRafal Jaworowski addr_cells = 2; 29658158742SRafal Jaworowski 29758158742SRafal Jaworowski return ((int)fdt32_to_cpu(addr_cells)); 29858158742SRafal Jaworowski } 29958158742SRafal Jaworowski 30058158742SRafal Jaworowski int 30158158742SRafal Jaworowski fdt_data_verify(void *data, int cells) 30258158742SRafal Jaworowski { 30358158742SRafal Jaworowski uint64_t d64; 30458158742SRafal Jaworowski 30558158742SRafal Jaworowski if (cells > 1) { 30658158742SRafal Jaworowski d64 = fdt64_to_cpu(*((uint64_t *)data)); 30758158742SRafal Jaworowski if (((d64 >> 32) & 0xffffffffull) != 0 || cells > 2) 30858158742SRafal Jaworowski return (ERANGE); 30958158742SRafal Jaworowski } 31058158742SRafal Jaworowski 31158158742SRafal Jaworowski return (0); 31258158742SRafal Jaworowski } 31358158742SRafal Jaworowski 31458158742SRafal Jaworowski int 31558158742SRafal Jaworowski fdt_pm_is_enabled(phandle_t node) 31658158742SRafal Jaworowski { 31758158742SRafal Jaworowski int ret; 31858158742SRafal Jaworowski 31958158742SRafal Jaworowski ret = 1; 32058158742SRafal Jaworowski 32158158742SRafal Jaworowski #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 32258158742SRafal Jaworowski ret = fdt_pm(node); 32358158742SRafal Jaworowski #endif 32458158742SRafal Jaworowski return (ret); 32558158742SRafal Jaworowski } 32658158742SRafal Jaworowski 32758158742SRafal Jaworowski u_long 32858158742SRafal Jaworowski fdt_data_get(void *data, int cells) 32958158742SRafal Jaworowski { 33058158742SRafal Jaworowski 33158158742SRafal Jaworowski if (cells == 1) 33258158742SRafal Jaworowski return (fdt32_to_cpu(*((uint32_t *)data))); 33358158742SRafal Jaworowski 33458158742SRafal Jaworowski return (fdt64_to_cpu(*((uint64_t *)data))); 33558158742SRafal Jaworowski } 33658158742SRafal Jaworowski 33758158742SRafal Jaworowski int 33858158742SRafal Jaworowski fdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells) 33958158742SRafal Jaworowski { 34058158742SRafal Jaworowski pcell_t cell; 34158158742SRafal Jaworowski int cell_size; 34258158742SRafal Jaworowski 34358158742SRafal Jaworowski /* 34458158742SRafal Jaworowski * Retrieve #{address,size}-cells. 34558158742SRafal Jaworowski */ 34658158742SRafal Jaworowski cell_size = sizeof(cell); 34758158742SRafal Jaworowski if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size) 34858158742SRafal Jaworowski cell = 2; 34958158742SRafal Jaworowski *addr_cells = fdt32_to_cpu((int)cell); 35058158742SRafal Jaworowski 35158158742SRafal Jaworowski if (OF_getprop(node, "#size-cells", &cell, cell_size) < cell_size) 35258158742SRafal Jaworowski cell = 1; 35358158742SRafal Jaworowski *size_cells = fdt32_to_cpu((int)cell); 35458158742SRafal Jaworowski 35558158742SRafal Jaworowski if (*addr_cells > 3 || *size_cells > 2) 35658158742SRafal Jaworowski return (ERANGE); 35758158742SRafal Jaworowski return (0); 35858158742SRafal Jaworowski } 35958158742SRafal Jaworowski 36058158742SRafal Jaworowski int 36158158742SRafal Jaworowski fdt_ranges_verify(pcell_t *ranges, int tuples, int par_addr_cells, 36258158742SRafal Jaworowski int this_addr_cells, int this_size_cells) 36358158742SRafal Jaworowski { 36458158742SRafal Jaworowski int i, rv, ulsz; 36558158742SRafal Jaworowski 36658158742SRafal Jaworowski if (par_addr_cells > 2 || this_addr_cells > 2 || this_size_cells > 2) 36758158742SRafal Jaworowski return (ERANGE); 36858158742SRafal Jaworowski 36958158742SRafal Jaworowski /* 37058158742SRafal Jaworowski * This is the max size the resource manager can handle for addresses 37158158742SRafal Jaworowski * and sizes. 37258158742SRafal Jaworowski */ 37358158742SRafal Jaworowski ulsz = sizeof(u_long); 37458158742SRafal Jaworowski if (par_addr_cells <= ulsz && this_addr_cells <= ulsz && 37558158742SRafal Jaworowski this_size_cells <= ulsz) 37658158742SRafal Jaworowski /* We can handle everything */ 37758158742SRafal Jaworowski return (0); 37858158742SRafal Jaworowski 37958158742SRafal Jaworowski rv = 0; 38058158742SRafal Jaworowski for (i = 0; i < tuples; i++) { 38158158742SRafal Jaworowski 38258158742SRafal Jaworowski if (fdt_data_verify((void *)ranges, par_addr_cells)) 38358158742SRafal Jaworowski goto err; 38458158742SRafal Jaworowski ranges += par_addr_cells; 38558158742SRafal Jaworowski 38658158742SRafal Jaworowski if (fdt_data_verify((void *)ranges, this_addr_cells)) 38758158742SRafal Jaworowski goto err; 38858158742SRafal Jaworowski ranges += this_addr_cells; 38958158742SRafal Jaworowski 39058158742SRafal Jaworowski if (fdt_data_verify((void *)ranges, this_size_cells)) 39158158742SRafal Jaworowski goto err; 39258158742SRafal Jaworowski ranges += this_size_cells; 39358158742SRafal Jaworowski } 39458158742SRafal Jaworowski 39558158742SRafal Jaworowski return (0); 39658158742SRafal Jaworowski 39758158742SRafal Jaworowski err: 39858158742SRafal Jaworowski debugf("using address range >%d-bit not supported\n", ulsz * 8); 39958158742SRafal Jaworowski return (ERANGE); 40058158742SRafal Jaworowski } 40158158742SRafal Jaworowski 40258158742SRafal Jaworowski int 40358158742SRafal Jaworowski fdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start, 40458158742SRafal Jaworowski u_long *count) 40558158742SRafal Jaworowski { 40658158742SRafal Jaworowski 40758158742SRafal Jaworowski /* Address portion. */ 40858158742SRafal Jaworowski if (fdt_data_verify((void *)data, addr_cells)) 40958158742SRafal Jaworowski return (ERANGE); 41058158742SRafal Jaworowski 41158158742SRafal Jaworowski *start = fdt_data_get((void *)data, addr_cells); 41258158742SRafal Jaworowski data += addr_cells; 41358158742SRafal Jaworowski 41458158742SRafal Jaworowski /* Size portion. */ 41558158742SRafal Jaworowski if (fdt_data_verify((void *)data, size_cells)) 41658158742SRafal Jaworowski return (ERANGE); 41758158742SRafal Jaworowski 41858158742SRafal Jaworowski *count = fdt_data_get((void *)data, size_cells); 41958158742SRafal Jaworowski return (0); 42058158742SRafal Jaworowski } 42158158742SRafal Jaworowski 42258158742SRafal Jaworowski int 42358158742SRafal Jaworowski fdt_regsize(phandle_t node, u_long *base, u_long *size) 42458158742SRafal Jaworowski { 42558158742SRafal Jaworowski pcell_t reg[4]; 42658158742SRafal Jaworowski int addr_cells, len, size_cells; 42758158742SRafal Jaworowski 42858158742SRafal Jaworowski if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells)) 42958158742SRafal Jaworowski return (ENXIO); 43058158742SRafal Jaworowski 43158158742SRafal Jaworowski if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg)) 43258158742SRafal Jaworowski return (ENOMEM); 43358158742SRafal Jaworowski 43458158742SRafal Jaworowski len = OF_getprop(node, "reg", ®, sizeof(reg)); 43558158742SRafal Jaworowski if (len <= 0) 43658158742SRafal Jaworowski return (EINVAL); 43758158742SRafal Jaworowski 43858158742SRafal Jaworowski *base = fdt_data_get(®[0], addr_cells); 43958158742SRafal Jaworowski *size = fdt_data_get(®[addr_cells], size_cells); 44058158742SRafal Jaworowski return (0); 44158158742SRafal Jaworowski } 44258158742SRafal Jaworowski 44358158742SRafal Jaworowski int 4448bb93637SOleksandr Tymoshenko fdt_reg_to_rl(phandle_t node, struct resource_list *rl) 44558158742SRafal Jaworowski { 4465ac9d989SAleksandr Rybalko u_long end, count, start; 44758158742SRafal Jaworowski pcell_t *reg, *regptr; 44858158742SRafal Jaworowski pcell_t addr_cells, size_cells; 44958158742SRafal Jaworowski int tuple_size, tuples; 45058158742SRafal Jaworowski int i, rv; 4518bb93637SOleksandr Tymoshenko long busaddr, bussize; 45258158742SRafal Jaworowski 45358158742SRafal Jaworowski if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 45458158742SRafal Jaworowski return (ENXIO); 4552f0da24bSGrzegorz Bernacki if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) { 4562f0da24bSGrzegorz Bernacki busaddr = 0; 4572f0da24bSGrzegorz Bernacki bussize = 0; 4582f0da24bSGrzegorz Bernacki } 45958158742SRafal Jaworowski 46058158742SRafal Jaworowski tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 46158158742SRafal Jaworowski tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); 46258158742SRafal Jaworowski debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 46358158742SRafal Jaworowski debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 46458158742SRafal Jaworowski if (tuples <= 0) 46558158742SRafal Jaworowski /* No 'reg' property in this node. */ 46658158742SRafal Jaworowski return (0); 46758158742SRafal Jaworowski 46858158742SRafal Jaworowski regptr = reg; 46958158742SRafal Jaworowski for (i = 0; i < tuples; i++) { 47058158742SRafal Jaworowski 4715ac9d989SAleksandr Rybalko rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, 4725ac9d989SAleksandr Rybalko &count); 47358158742SRafal Jaworowski if (rv != 0) { 47458158742SRafal Jaworowski resource_list_free(rl); 47558158742SRafal Jaworowski goto out; 47658158742SRafal Jaworowski } 47758158742SRafal Jaworowski reg += addr_cells + size_cells; 47858158742SRafal Jaworowski 47958158742SRafal Jaworowski /* Calculate address range relative to base. */ 4808bb93637SOleksandr Tymoshenko start += busaddr; 4814117c1dbSAleksandr Rybalko end = start + count - 1; 48258158742SRafal Jaworowski 4834117c1dbSAleksandr Rybalko debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, 48458158742SRafal Jaworowski end, count); 48558158742SRafal Jaworowski 4864117c1dbSAleksandr Rybalko resource_list_add(rl, SYS_RES_MEMORY, i, start, end, 48758158742SRafal Jaworowski count); 48858158742SRafal Jaworowski } 48958158742SRafal Jaworowski rv = 0; 49058158742SRafal Jaworowski 49158158742SRafal Jaworowski out: 49258158742SRafal Jaworowski free(regptr, M_OFWPROP); 49358158742SRafal Jaworowski return (rv); 49458158742SRafal Jaworowski } 49558158742SRafal Jaworowski 49658158742SRafal Jaworowski int 49767dbd33cSNathan Whitehorn fdt_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl, 49858158742SRafal Jaworowski struct fdt_sense_level *intr_sl) 49958158742SRafal Jaworowski { 50067dbd33cSNathan Whitehorn phandle_t iparent; 50167dbd33cSNathan Whitehorn uint32_t *intr, icells; 50267dbd33cSNathan Whitehorn int nintr, i, k; 50358158742SRafal Jaworowski 50467dbd33cSNathan Whitehorn nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), 50567dbd33cSNathan Whitehorn (void **)&intr); 50667dbd33cSNathan Whitehorn if (nintr > 0) { 507f2a7dc98SIan Lepore if (OF_searchencprop(node, "interrupt-parent", &iparent, 508f2a7dc98SIan Lepore sizeof(iparent)) == -1) { 509f2a7dc98SIan Lepore device_printf(dev, "No interrupt-parent found, " 510f2a7dc98SIan Lepore "assuming direct parent\n"); 511f2a7dc98SIan Lepore iparent = OF_parent(node); 512f2a7dc98SIan Lepore } 513*752ba930SIan Lepore if (OF_searchencprop(OF_node_from_xref(iparent), 514f2a7dc98SIan Lepore "#interrupt-cells", &icells, sizeof(icells)) == -1) { 515f2a7dc98SIan Lepore device_printf(dev, "Missing #interrupt-cells property, " 516f2a7dc98SIan Lepore "assuming <1>\n"); 517f2a7dc98SIan Lepore icells = 1; 518f2a7dc98SIan Lepore } 519f2a7dc98SIan Lepore if (icells < 1 || icells > nintr) { 520f2a7dc98SIan Lepore device_printf(dev, "Invalid #interrupt-cells property " 521f2a7dc98SIan Lepore "value <%d>, assuming <1>\n", icells); 522f2a7dc98SIan Lepore icells = 1; 523f2a7dc98SIan Lepore } 52467dbd33cSNathan Whitehorn for (i = 0, k = 0; i < nintr; i += icells, k++) { 525f18ac51aSNathan Whitehorn intr[i] = ofw_bus_map_intr(dev, iparent, icells, 526f18ac51aSNathan Whitehorn &intr[i]); 52767dbd33cSNathan Whitehorn resource_list_add(rl, SYS_RES_IRQ, k, intr[i], intr[i], 52867dbd33cSNathan Whitehorn 1); 52958158742SRafal Jaworowski } 53058158742SRafal Jaworowski free(intr, M_OFWPROP); 53167dbd33cSNathan Whitehorn } 53267dbd33cSNathan Whitehorn 53367dbd33cSNathan Whitehorn return (0); 53458158742SRafal Jaworowski } 53558158742SRafal Jaworowski 53658158742SRafal Jaworowski int 537aa15e881SRafal Jaworowski fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) 53858158742SRafal Jaworowski { 53958158742SRafal Jaworowski phandle_t phy_node; 54058158742SRafal Jaworowski pcell_t phy_handle, phy_reg; 541aa15e881SRafal Jaworowski uint32_t i; 542aa15e881SRafal Jaworowski device_t parent, child; 54358158742SRafal Jaworowski 544755c9591SNathan Whitehorn if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 54558158742SRafal Jaworowski sizeof(phy_handle)) <= 0) 54658158742SRafal Jaworowski return (ENXIO); 54758158742SRafal Jaworowski 548*752ba930SIan Lepore phy_node = OF_node_from_xref(phy_handle); 54958158742SRafal Jaworowski 55058158742SRafal Jaworowski if (OF_getprop(phy_node, "reg", (void *)&phy_reg, 55158158742SRafal Jaworowski sizeof(phy_reg)) <= 0) 55258158742SRafal Jaworowski return (ENXIO); 55358158742SRafal Jaworowski 55458158742SRafal Jaworowski *phy_addr = fdt32_to_cpu(phy_reg); 555aa15e881SRafal Jaworowski 556aa15e881SRafal Jaworowski /* 557aa15e881SRafal Jaworowski * Search for softc used to communicate with phy. 558aa15e881SRafal Jaworowski */ 559aa15e881SRafal Jaworowski 560aa15e881SRafal Jaworowski /* 561aa15e881SRafal Jaworowski * Step 1: Search for ancestor of the phy-node with a "phy-handle" 562aa15e881SRafal Jaworowski * property set. 563aa15e881SRafal Jaworowski */ 564aa15e881SRafal Jaworowski phy_node = OF_parent(phy_node); 565aa15e881SRafal Jaworowski while (phy_node != 0) { 566aa15e881SRafal Jaworowski if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, 567aa15e881SRafal Jaworowski sizeof(phy_handle)) > 0) 568aa15e881SRafal Jaworowski break; 569aa15e881SRafal Jaworowski phy_node = OF_parent(phy_node); 570aa15e881SRafal Jaworowski } 571aa15e881SRafal Jaworowski if (phy_node == 0) 572aa15e881SRafal Jaworowski return (ENXIO); 573aa15e881SRafal Jaworowski 574aa15e881SRafal Jaworowski /* 575aa15e881SRafal Jaworowski * Step 2: For each device with the same parent and name as ours 576aa15e881SRafal Jaworowski * compare its node with the one found in step 1, ancestor of phy 577aa15e881SRafal Jaworowski * node (stored in phy_node). 578aa15e881SRafal Jaworowski */ 579aa15e881SRafal Jaworowski parent = device_get_parent(dev); 580aa15e881SRafal Jaworowski i = 0; 581aa15e881SRafal Jaworowski child = device_find_child(parent, device_get_name(dev), i); 582aa15e881SRafal Jaworowski while (child != NULL) { 583aa15e881SRafal Jaworowski if (ofw_bus_get_node(child) == phy_node) 584aa15e881SRafal Jaworowski break; 585aa15e881SRafal Jaworowski i++; 586aa15e881SRafal Jaworowski child = device_find_child(parent, device_get_name(dev), i); 587aa15e881SRafal Jaworowski } 588aa15e881SRafal Jaworowski if (child == NULL) 589aa15e881SRafal Jaworowski return (ENXIO); 590aa15e881SRafal Jaworowski 591aa15e881SRafal Jaworowski /* 592aa15e881SRafal Jaworowski * Use softc of the device found. 593aa15e881SRafal Jaworowski */ 594aa15e881SRafal Jaworowski *phy_sc = (void *)device_get_softc(child); 595aa15e881SRafal Jaworowski 59658158742SRafal Jaworowski return (0); 59758158742SRafal Jaworowski } 59858158742SRafal Jaworowski 59958158742SRafal Jaworowski int 6001d1ffd9eSOleksandr Tymoshenko fdt_get_reserved_regions(struct mem_region *mr, int *mrcnt) 6011d1ffd9eSOleksandr Tymoshenko { 6021d1ffd9eSOleksandr Tymoshenko pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS]; 6031d1ffd9eSOleksandr Tymoshenko pcell_t *reservep; 6041d1ffd9eSOleksandr Tymoshenko phandle_t memory, root; 6051d1ffd9eSOleksandr Tymoshenko uint32_t memory_size; 6061d1ffd9eSOleksandr Tymoshenko int addr_cells, size_cells; 6071d1ffd9eSOleksandr Tymoshenko int i, max_size, res_len, rv, tuple_size, tuples; 6081d1ffd9eSOleksandr Tymoshenko 6091d1ffd9eSOleksandr Tymoshenko max_size = sizeof(reserve); 6101d1ffd9eSOleksandr Tymoshenko root = OF_finddevice("/"); 6111d1ffd9eSOleksandr Tymoshenko memory = OF_finddevice("/memory"); 6121d1ffd9eSOleksandr Tymoshenko if (memory == -1) { 6131d1ffd9eSOleksandr Tymoshenko rv = ENXIO; 6141d1ffd9eSOleksandr Tymoshenko goto out; 6151d1ffd9eSOleksandr Tymoshenko } 6161d1ffd9eSOleksandr Tymoshenko 6171d1ffd9eSOleksandr Tymoshenko if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 6181d1ffd9eSOleksandr Tymoshenko &size_cells)) != 0) 6191d1ffd9eSOleksandr Tymoshenko goto out; 6201d1ffd9eSOleksandr Tymoshenko 6211d1ffd9eSOleksandr Tymoshenko if (addr_cells > 2) { 6221d1ffd9eSOleksandr Tymoshenko rv = ERANGE; 6231d1ffd9eSOleksandr Tymoshenko goto out; 6241d1ffd9eSOleksandr Tymoshenko } 6251d1ffd9eSOleksandr Tymoshenko 6261d1ffd9eSOleksandr Tymoshenko tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 6271d1ffd9eSOleksandr Tymoshenko 6281d1ffd9eSOleksandr Tymoshenko res_len = OF_getproplen(root, "memreserve"); 6291d1ffd9eSOleksandr Tymoshenko if (res_len <= 0 || res_len > sizeof(reserve)) { 6301d1ffd9eSOleksandr Tymoshenko rv = ERANGE; 6311d1ffd9eSOleksandr Tymoshenko goto out; 6321d1ffd9eSOleksandr Tymoshenko } 6331d1ffd9eSOleksandr Tymoshenko 6341d1ffd9eSOleksandr Tymoshenko if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) { 6351d1ffd9eSOleksandr Tymoshenko rv = ENXIO; 6361d1ffd9eSOleksandr Tymoshenko goto out; 6371d1ffd9eSOleksandr Tymoshenko } 6381d1ffd9eSOleksandr Tymoshenko 6391d1ffd9eSOleksandr Tymoshenko memory_size = 0; 6401d1ffd9eSOleksandr Tymoshenko tuples = res_len / tuple_size; 6411d1ffd9eSOleksandr Tymoshenko reservep = (pcell_t *)&reserve; 6421d1ffd9eSOleksandr Tymoshenko for (i = 0; i < tuples; i++) { 6431d1ffd9eSOleksandr Tymoshenko 6441d1ffd9eSOleksandr Tymoshenko rv = fdt_data_to_res(reservep, addr_cells, size_cells, 6451d1ffd9eSOleksandr Tymoshenko (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 6461d1ffd9eSOleksandr Tymoshenko 6471d1ffd9eSOleksandr Tymoshenko if (rv != 0) 6481d1ffd9eSOleksandr Tymoshenko goto out; 6491d1ffd9eSOleksandr Tymoshenko 6501d1ffd9eSOleksandr Tymoshenko reservep += addr_cells + size_cells; 6511d1ffd9eSOleksandr Tymoshenko } 6521d1ffd9eSOleksandr Tymoshenko 6531d1ffd9eSOleksandr Tymoshenko *mrcnt = i; 6541d1ffd9eSOleksandr Tymoshenko rv = 0; 6551d1ffd9eSOleksandr Tymoshenko out: 6561d1ffd9eSOleksandr Tymoshenko return (rv); 6571d1ffd9eSOleksandr Tymoshenko } 6581d1ffd9eSOleksandr Tymoshenko 6591d1ffd9eSOleksandr Tymoshenko int 66058158742SRafal Jaworowski fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize) 66158158742SRafal Jaworowski { 66258158742SRafal Jaworowski pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; 66358158742SRafal Jaworowski pcell_t *regp; 66458158742SRafal Jaworowski phandle_t memory; 66558158742SRafal Jaworowski uint32_t memory_size; 66658158742SRafal Jaworowski int addr_cells, size_cells; 66758158742SRafal Jaworowski int i, max_size, reg_len, rv, tuple_size, tuples; 66858158742SRafal Jaworowski 66958158742SRafal Jaworowski max_size = sizeof(reg); 67058158742SRafal Jaworowski memory = OF_finddevice("/memory"); 67107042befSJayachandran C. if (memory == -1) { 67258158742SRafal Jaworowski rv = ENXIO; 67358158742SRafal Jaworowski goto out; 67458158742SRafal Jaworowski } 67558158742SRafal Jaworowski 67658158742SRafal Jaworowski if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, 67758158742SRafal Jaworowski &size_cells)) != 0) 67858158742SRafal Jaworowski goto out; 67958158742SRafal Jaworowski 68058158742SRafal Jaworowski if (addr_cells > 2) { 68158158742SRafal Jaworowski rv = ERANGE; 68258158742SRafal Jaworowski goto out; 68358158742SRafal Jaworowski } 68458158742SRafal Jaworowski 68558158742SRafal Jaworowski tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 68658158742SRafal Jaworowski reg_len = OF_getproplen(memory, "reg"); 68758158742SRafal Jaworowski if (reg_len <= 0 || reg_len > sizeof(reg)) { 68858158742SRafal Jaworowski rv = ERANGE; 68958158742SRafal Jaworowski goto out; 69058158742SRafal Jaworowski } 69158158742SRafal Jaworowski 69258158742SRafal Jaworowski if (OF_getprop(memory, "reg", reg, reg_len) <= 0) { 69358158742SRafal Jaworowski rv = ENXIO; 69458158742SRafal Jaworowski goto out; 69558158742SRafal Jaworowski } 69658158742SRafal Jaworowski 69758158742SRafal Jaworowski memory_size = 0; 69858158742SRafal Jaworowski tuples = reg_len / tuple_size; 69958158742SRafal Jaworowski regp = (pcell_t *)® 70058158742SRafal Jaworowski for (i = 0; i < tuples; i++) { 70158158742SRafal Jaworowski 70258158742SRafal Jaworowski rv = fdt_data_to_res(regp, addr_cells, size_cells, 70358158742SRafal Jaworowski (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); 70458158742SRafal Jaworowski 70558158742SRafal Jaworowski if (rv != 0) 70658158742SRafal Jaworowski goto out; 70758158742SRafal Jaworowski 70858158742SRafal Jaworowski regp += addr_cells + size_cells; 70958158742SRafal Jaworowski memory_size += mr[i].mr_size; 71058158742SRafal Jaworowski } 71158158742SRafal Jaworowski 71258158742SRafal Jaworowski if (memory_size == 0) { 71358158742SRafal Jaworowski rv = ERANGE; 71458158742SRafal Jaworowski goto out; 71558158742SRafal Jaworowski } 71658158742SRafal Jaworowski 71758158742SRafal Jaworowski *mrcnt = i; 71858158742SRafal Jaworowski *memsize = memory_size; 71958158742SRafal Jaworowski rv = 0; 72058158742SRafal Jaworowski out: 72158158742SRafal Jaworowski return (rv); 72258158742SRafal Jaworowski } 7232c990564SGrzegorz Bernacki 7242c990564SGrzegorz Bernacki int 7252c990564SGrzegorz Bernacki fdt_get_unit(device_t dev) 7262c990564SGrzegorz Bernacki { 7272c990564SGrzegorz Bernacki const char * name; 7282c990564SGrzegorz Bernacki 7292c990564SGrzegorz Bernacki name = ofw_bus_get_name(dev); 7302c990564SGrzegorz Bernacki name = strchr(name, '@') + 1; 7312c990564SGrzegorz Bernacki 7322c990564SGrzegorz Bernacki return (strtol(name,NULL,0)); 7332c990564SGrzegorz Bernacki } 734