X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fcore%2Fofnode.c;h=0cfb0fbabb008f45798c49ddbf2ce9148ba57b15;hb=4f10989280bb91f0981ffe2ffabe936bb2a92364;hp=c1a2e9f0daefdffef2b7087e91d5b23f86bb1c6e;hpb=2218b32d88f9b4b4484cea9a8b034ddab0be298b;p=oweals%2Fu-boot.git diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index c1a2e9f0da..0cfb0fbabb 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1,15 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2017 Google, Inc * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include -#include +#include #include #include #include @@ -56,6 +55,38 @@ int ofnode_read_s32_default(ofnode node, const char *propname, s32 def) return def; } +int ofnode_read_u64(ofnode node, const char *propname, u64 *outp) +{ + const fdt64_t *cell; + int len; + + assert(ofnode_valid(node)); + debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) + return of_read_u64(ofnode_to_np(node), propname, outp); + + cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname, + &len); + if (!cell || len < sizeof(*cell)) { + debug("(not found)\n"); + return -EINVAL; + } + *outp = fdt64_to_cpu(cell[0]); + debug("%#llx (%lld)\n", (unsigned long long)*outp, + (unsigned long long)*outp); + + return 0; +} + +int ofnode_read_u64_default(ofnode node, const char *propname, u64 def) +{ + assert(ofnode_valid(node)); + ofnode_read_u64(node, propname, &def); + + return def; +} + bool ofnode_read_bool(ofnode node, const char *propname) { const void *prop; @@ -165,6 +196,20 @@ ofnode ofnode_next_subnode(ofnode node) fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node))); } +ofnode ofnode_get_parent(ofnode node) +{ + ofnode parent; + + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) + parent = np_to_ofnode(of_get_parent(ofnode_to_np(node))); + else + parent.of_offset = fdt_parent_offset(gd->fdt_blob, + ofnode_to_offset(node)); + + return parent; +} + const char *ofnode_get_name(ofnode node) { assert(ofnode_valid(node)); @@ -174,6 +219,19 @@ const char *ofnode_get_name(ofnode node) return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL); } +ofnode ofnode_get_by_phandle(uint phandle) +{ + ofnode node; + + if (of_live_active()) + node = np_to_ofnode(of_find_node_by_phandle(phandle)); + else + node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob, + phandle); + + return node; +} + int ofnode_read_size(ofnode node, const char *propname) { int len; @@ -200,13 +258,21 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index) uint flags; u64 size; int na; + int ns; prop_val = of_get_address(ofnode_to_np(node), index, &size, &flags); if (!prop_val) return FDT_ADDR_T_NONE; - na = of_n_addr_cells(ofnode_to_np(node)); - return of_read_number(prop_val, na); + + ns = of_n_size_cells(ofnode_to_np(node)); + + if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) { + return of_translate_address(ofnode_to_np(node), prop_val); + } else { + na = of_n_addr_cells(ofnode_to_np(node)); + return of_read_number(prop_val, na); + } } else { return fdt_get_base_address(gd->fdt_blob, ofnode_to_offset(node)); @@ -296,7 +362,8 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, int ret; ret = of_parse_phandle_with_args(ofnode_to_np(node), - list_name, cells_name, index, &args); + list_name, cells_name, index, + &args); if (ret) return ret; ofnode_from_of_phandle_args(&args, out_args); @@ -305,8 +372,9 @@ int ofnode_parse_phandle_with_args(ofnode node, const char *list_name, int ret; ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, - ofnode_to_offset(node), list_name, cells_name, - cell_count, index, &args); + ofnode_to_offset(node), + list_name, cells_name, + cell_count, index, &args); if (ret) return ret; ofnode_from_fdtdec_phandle_args(&args, out_args); @@ -390,10 +458,11 @@ int ofnode_decode_display_timing(ofnode parent, int index, if (!ofnode_valid(timings)) return -EINVAL; - for (i = 0, node = ofnode_first_subnode(timings); - ofnode_valid(node) && i != index; - node = ofnode_first_subnode(node)) - i++; + i = 0; + ofnode_for_each_subnode(node, timings) { + if (i++ == index) + break; + } if (!ofnode_valid(node)) return -EINVAL; @@ -467,8 +536,10 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property, int na, ns; int psize; const struct device_node *np = ofnode_to_np(node); - const __be32 *prop = of_get_property(np, "reg", &psize); + const __be32 *prop = of_get_property(np, property, &psize); + if (!prop) + return FDT_ADDR_T_NONE; na = of_n_addr_cells(np); ns = of_n_addr_cells(np); *sizep = of_read_number(prop + na, ns); @@ -531,10 +602,10 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, addr->phys_mid = fdt32_to_cpu(cell[1]); addr->phys_lo = fdt32_to_cpu(cell[1]); break; - } else { - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); } + + cell += (FDT_PCI_ADDR_CELLS + + FDT_PCI_SIZE_CELLS); } if (i == num) { @@ -543,15 +614,51 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, } return 0; - } else { - ret = -EINVAL; } + ret = -EINVAL; + fail: debug("(not found)\n"); return ret; } +int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device) +{ + const char *list, *end; + int len; + + list = ofnode_get_property(node, "compatible", &len); + if (!list) + return -ENOENT; + + end = list + len; + while (list < end) { + len = strlen(list); + if (len >= strlen("pciVVVV,DDDD")) { + char *s = strstr(list, "pci"); + + /* + * check if the string is something like pciVVVV,DDDD.RR + * or just pciVVVV,DDDD + */ + if (s && s[7] == ',' && + (s[12] == '.' || s[12] == 0)) { + s += 3; + *vendor = simple_strtol(s, NULL, 16); + + s += 5; + *device = simple_strtol(s, NULL, 16); + + return 0; + } + } + list += (len + 1); + } + + return -ENOENT; +} + int ofnode_read_addr_cells(ofnode node) { if (ofnode_is_np(node)) @@ -627,3 +734,46 @@ int ofnode_read_resource(ofnode node, uint index, struct resource *res) return 0; } } + +int ofnode_read_resource_byname(ofnode node, const char *name, + struct resource *res) +{ + int index; + + index = ofnode_stringlist_search(node, "reg-names", name); + if (index < 0) + return index; + + return ofnode_read_resource(node, index, res); +} + +u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr) +{ + if (ofnode_is_np(node)) + return of_translate_address(ofnode_to_np(node), in_addr); + else + return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr); +} + +int ofnode_device_is_compatible(ofnode node, const char *compat) +{ + if (ofnode_is_np(node)) + return of_device_is_compatible(ofnode_to_np(node), compat, + NULL, NULL); + else + return !fdt_node_check_compatible(gd->fdt_blob, + ofnode_to_offset(node), + compat); +} + +ofnode ofnode_by_compatible(ofnode from, const char *compat) +{ + if (of_live_active()) { + return np_to_ofnode(of_find_compatible_node( + (struct device_node *)ofnode_to_np(from), NULL, + compat)); + } else { + return offset_to_ofnode(fdt_node_offset_by_compatible( + gd->fdt_blob, ofnode_to_offset(from), compat)); + } +}