X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fcore%2Fofnode.c;h=b7b7ad3a625da9cbff62bed3644067eabc72ac1f;hb=3d5ced9e22d32112a20f9dc0f5fb1f22ef088079;hp=c6ca13fabf1f7fbf1ab462d89a400057f89c98e7;hpb=8a33cb8b6bdf8a35f931fcc3d8aa15254cfc4b23;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index c6ca13f..b7b7ad3 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); @@ -468,12 +536,18 @@ 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); + ns = of_n_size_cells(np); *sizep = of_read_number(prop + na, ns); - return of_read_number(prop, na); + + if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) + return of_translate_address(np, prop); + else + return of_read_number(prop, na); } else { return fdtdec_get_addr_size(gd->fdt_blob, ofnode_to_offset(node), property, @@ -532,10 +606,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) { @@ -544,15 +618,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)) @@ -589,6 +699,8 @@ bool ofnode_pre_reloc(ofnode node) { if (ofnode_read_bool(node, "u-boot,dm-pre-reloc")) return true; + if (ofnode_read_bool(node, "u-boot,dm-pre-proper")) + return true; #ifdef CONFIG_TPL_BUILD if (ofnode_read_bool(node, "u-boot,dm-tpl")) @@ -640,3 +752,118 @@ int ofnode_read_resource_byname(ofnode node, const char *name, 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)); + } +} + +ofnode ofnode_by_prop_value(ofnode from, const char *propname, + const void *propval, int proplen) +{ + if (of_live_active()) { + return np_to_ofnode(of_find_node_by_prop_value( + (struct device_node *)ofnode_to_np(from), propname, + propval, proplen)); + } else { + return offset_to_ofnode(fdt_node_offset_by_prop_value( + gd->fdt_blob, ofnode_to_offset(from), + propname, propval, proplen)); + } +} + +int ofnode_write_prop(ofnode node, const char *propname, int len, + const void *value) +{ + const struct device_node *np = ofnode_to_np(node); + struct property *pp; + struct property *pp_last = NULL; + struct property *new; + + if (!of_live_active()) + return -ENOSYS; + + if (!np) + return -EINVAL; + + for (pp = np->properties; pp; pp = pp->next) { + if (strcmp(pp->name, propname) == 0) { + /* Property exists -> change value */ + pp->value = (void *)value; + pp->length = len; + return 0; + } + pp_last = pp; + } + + if (!pp_last) + return -ENOENT; + + /* Property does not exist -> append new property */ + new = malloc(sizeof(struct property)); + if (!new) + return -ENOMEM; + + new->name = strdup(propname); + if (!new->name) + return -ENOMEM; + + new->value = (void *)value; + new->length = len; + new->next = NULL; + + pp_last->next = new; + + return 0; +} + +int ofnode_write_string(ofnode node, const char *propname, const char *value) +{ + if (!of_live_active()) + return -ENOSYS; + + assert(ofnode_valid(node)); + + debug("%s: %s = %s", __func__, propname, value); + + return ofnode_write_prop(node, propname, strlen(value) + 1, value); +} + +int ofnode_set_enabled(ofnode node, bool value) +{ + if (!of_live_active()) + return -ENOSYS; + + assert(ofnode_valid(node)); + + if (value) + return ofnode_write_string(node, "status", "okay"); + else + return ofnode_write_string(node, "status", "disable"); +}