diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/address.c | 29 | ||||
-rw-r--r-- | drivers/of/of_mdio.c | 4 | ||||
-rw-r--r-- | drivers/of/of_reserved_mem.c | 14 | ||||
-rw-r--r-- | drivers/of/property.c | 112 | ||||
-rw-r--r-- | drivers/of/unittest-data/tests-address.dtsi | 10 | ||||
-rw-r--r-- | drivers/of/unittest.c | 2 |
6 files changed, 139 insertions, 32 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index 8eea3f6e29a4..590493e04b01 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -49,6 +49,7 @@ struct of_bus { u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna); int (*translate)(__be32 *addr, u64 offset, int na); + bool has_flags; unsigned int (*get_flags)(const __be32 *addr); }; @@ -100,6 +101,7 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr) return IORESOURCE_MEM; } +#ifdef CONFIG_PCI static unsigned int of_bus_pci_get_flags(const __be32 *addr) { unsigned int flags = 0; @@ -122,7 +124,6 @@ static unsigned int of_bus_pci_get_flags(const __be32 *addr) return flags; } -#ifdef CONFIG_PCI /* * PCI bus specific translator */ @@ -364,6 +365,7 @@ static struct of_bus of_busses[] = { .count_cells = of_bus_pci_count_cells, .map = of_bus_pci_map, .translate = of_bus_pci_translate, + .has_flags = true, .get_flags = of_bus_pci_get_flags, }, #endif /* CONFIG_PCI */ @@ -375,6 +377,7 @@ static struct of_bus of_busses[] = { .count_cells = of_bus_isa_count_cells, .map = of_bus_isa_map, .translate = of_bus_isa_translate, + .has_flags = true, .get_flags = of_bus_isa_get_flags, }, /* Default */ @@ -701,6 +704,7 @@ static int parser_init(struct of_pci_range_parser *parser, parser->na = of_bus_n_addr_cells(node); parser->ns = of_bus_n_size_cells(node); parser->dma = !strcmp(name, "dma-ranges"); + parser->bus = of_match_bus(node); parser->range = of_get_property(node, name, &rlen); if (parser->range == NULL) @@ -732,6 +736,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, int na = parser->na; int ns = parser->ns; int np = parser->pna + na + ns; + int busflag_na = 0; if (!range) return NULL; @@ -739,12 +744,13 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, if (!parser->range || parser->range + np > parser->end) return NULL; - if (parser->na == 3) - range->flags = of_bus_pci_get_flags(parser->range); - else - range->flags = 0; + range->flags = parser->bus->get_flags(parser->range); - range->pci_addr = of_read_number(parser->range, na); + /* A extra cell for resource flags */ + if (parser->bus->has_flags) + busflag_na = 1; + + range->bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na); if (parser->dma) range->cpu_addr = of_translate_dma_address(parser->node, @@ -759,11 +765,10 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, /* Now consume following elements while they are contiguous */ while (parser->range + np <= parser->end) { u32 flags = 0; - u64 pci_addr, cpu_addr, size; + u64 bus_addr, cpu_addr, size; - if (parser->na == 3) - flags = of_bus_pci_get_flags(parser->range); - pci_addr = of_read_number(parser->range, na); + flags = parser->bus->get_flags(parser->range); + bus_addr = of_read_number(parser->range + busflag_na, na - busflag_na); if (parser->dma) cpu_addr = of_translate_dma_address(parser->node, parser->range + na); @@ -774,7 +779,7 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, if (flags != range->flags) break; - if (pci_addr != range->pci_addr + range->size || + if (bus_addr != range->bus_addr + range->size || cpu_addr != range->cpu_addr + range->size) break; @@ -864,7 +869,7 @@ EXPORT_SYMBOL_GPL(of_address_to_resource); /** * of_iomap - Maps the memory mapped IO for a given device_node - * @device: the device whose io range will be mapped + * @np: the device whose io range will be mapped * @index: index of the io range * * Returns a pointer to the mapped memory diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index ef6f818ce5b3..cb32d7ef4938 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -268,6 +268,8 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) /* Get bus level PHY reset GPIO details */ mdio->reset_delay_us = DEFAULT_GPIO_RESET_DELAY; of_property_read_u32(np, "reset-delay-us", &mdio->reset_delay_us); + mdio->reset_post_delay_us = 0; + of_property_read_u32(np, "reset-post-delay-us", &mdio->reset_post_delay_us); /* Register the MDIO bus */ rc = mdiobus_register(mdio); @@ -385,7 +387,7 @@ struct phy_device *of_phy_connect(struct net_device *dev, if (!phy) return NULL; - phy->dev_flags = flags; + phy->dev_flags |= flags; ret = phy_connect_direct(dev, phy, hndlr, iface); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 6877080c8af9..46b9371c8a33 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -54,7 +54,7 @@ void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) { - pr_err("not enough space all defined regions.\n"); + pr_err("not enough space for all defined regions.\n"); return; } @@ -69,7 +69,7 @@ void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, /** * __reserved_mem_alloc_size() - allocate reserved memory described by - * 'size', 'align' and 'alloc-ranges' properties. + * 'size', 'alignment' and 'alloc-ranges' properties. */ static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname, phys_addr_t *res_base, phys_addr_t *res_size) @@ -79,7 +79,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node, phys_addr_t base = 0, align = 0, size; int len; const __be32 *prop; - int nomap; + bool nomap; int ret; prop = of_get_flat_dt_prop(node, "size", &len); @@ -92,8 +92,6 @@ static int __init __reserved_mem_alloc_size(unsigned long node, } size = dt_mem_next_cell(dt_root_size_cells, &prop); - nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; - prop = of_get_flat_dt_prop(node, "alignment", &len); if (prop) { if (len != dt_root_addr_cells * sizeof(__be32)) { @@ -104,11 +102,13 @@ static int __init __reserved_mem_alloc_size(unsigned long node, align = dt_mem_next_cell(dt_root_addr_cells, &prop); } + nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; + /* Need adjust the alignment to satisfy the CMA requirement */ if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool") && of_get_flat_dt_prop(node, "reusable", NULL) - && !of_get_flat_dt_prop(node, "no-map", NULL)) { + && !nomap) { unsigned long order = max_t(unsigned long, MAX_ORDER - 1, pageblock_order); @@ -247,7 +247,7 @@ void __init fdt_init_reserved_mem(void) int len; const __be32 *prop; int err = 0; - int nomap; + bool nomap; nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; prop = of_get_flat_dt_prop(node, "phandle", &len); diff --git a/drivers/of/property.c b/drivers/of/property.c index 1f2086f4e7ce..408a7b5f06a9 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -30,6 +30,29 @@ #include "of_private.h" /** + * of_graph_is_present() - check graph's presence + * @node: pointer to device_node containing graph port + * + * Return: True if @node has a port or ports (with a port) sub-node, + * false otherwise. + */ +bool of_graph_is_present(const struct device_node *node) +{ + struct device_node *ports, *port; + + ports = of_get_child_by_name(node, "ports"); + if (ports) + node = ports; + + port = of_get_child_by_name(node, "port"); + of_node_put(ports); + of_node_put(port); + + return !!port; +} +EXPORT_SYMBOL(of_graph_is_present); + +/** * of_property_count_elems_of_size - Count the number of elements in a property * * @np: device node from which the property value is to be read. @@ -1015,6 +1038,30 @@ static bool of_is_ancestor_of(struct device_node *test_ancestor, } /** + * of_get_next_parent_dev - Add device link to supplier from supplier phandle + * @np: device tree node + * + * Given a device tree node (@np), this function finds its closest ancestor + * device tree node that has a corresponding struct device. + * + * The caller of this function is expected to call put_device() on the returned + * device when they are done. + */ +static struct device *of_get_next_parent_dev(struct device_node *np) +{ + struct device *dev = NULL; + + of_node_get(np); + do { + np = of_get_next_parent(np); + if (np) + dev = get_dev_from_fwnode(&np->fwnode); + } while (np && !dev); + of_node_put(np); + return dev; +} + +/** * of_link_to_phandle - Add device link to supplier from supplier phandle * @dev: consumer device * @sup_np: phandle to supplier device tree node @@ -1035,10 +1082,9 @@ static bool of_is_ancestor_of(struct device_node *test_ancestor, static int of_link_to_phandle(struct device *dev, struct device_node *sup_np, u32 dl_flags) { - struct device *sup_dev; + struct device *sup_dev, *sup_par_dev; int ret = 0; struct device_node *tmp_np = sup_np; - int is_populated; of_node_get(sup_np); /* @@ -1075,16 +1121,43 @@ static int of_link_to_phandle(struct device *dev, struct device_node *sup_np, return -EINVAL; } sup_dev = get_dev_from_fwnode(&sup_np->fwnode); - is_populated = of_node_check_flag(sup_np, OF_POPULATED); - of_node_put(sup_np); - if (!sup_dev && is_populated) { + if (!sup_dev && of_node_check_flag(sup_np, OF_POPULATED)) { /* Early device without struct device. */ dev_dbg(dev, "Not linking to %pOFP - No struct device\n", sup_np); + of_node_put(sup_np); return -ENODEV; } else if (!sup_dev) { - return -EAGAIN; + /* + * DL_FLAG_SYNC_STATE_ONLY doesn't block probing and supports + * cycles. So cycle detection isn't necessary and shouldn't be + * done. + */ + if (dl_flags & DL_FLAG_SYNC_STATE_ONLY) { + of_node_put(sup_np); + return -EAGAIN; + } + + sup_par_dev = of_get_next_parent_dev(sup_np); + + if (sup_par_dev && device_is_dependent(dev, sup_par_dev)) { + /* Cyclic dependency detected, don't try to link */ + dev_dbg(dev, "Not linking to %pOFP - cycle detected\n", + sup_np); + ret = -EINVAL; + } else { + /* + * Can't check for cycles or no cycles. So let's try + * again later. + */ + ret = -EAGAIN; + } + + of_node_put(sup_np); + put_device(sup_par_dev); + return ret; } + of_node_put(sup_np); if (!device_link_add(dev, sup_dev, dl_flags)) ret = -EINVAL; put_device(sup_dev); @@ -1219,6 +1292,20 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells") DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells") DEFINE_SIMPLE_PROP(extcon, "extcon", NULL) +DEFINE_SIMPLE_PROP(interrupts_extended, "interrupts-extended", + "#interrupt-cells") +DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", NULL) +DEFINE_SIMPLE_PROP(phys, "phys", "#phy-cells") +DEFINE_SIMPLE_PROP(wakeup_parent, "wakeup-parent", NULL) +DEFINE_SIMPLE_PROP(pinctrl0, "pinctrl-0", NULL) +DEFINE_SIMPLE_PROP(pinctrl1, "pinctrl-1", NULL) +DEFINE_SIMPLE_PROP(pinctrl2, "pinctrl-2", NULL) +DEFINE_SIMPLE_PROP(pinctrl3, "pinctrl-3", NULL) +DEFINE_SIMPLE_PROP(pinctrl4, "pinctrl-4", NULL) +DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL) +DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL) +DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL) +DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL) DEFINE_SUFFIX_PROP(regulators, "-supply", NULL) DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells") DEFINE_SUFFIX_PROP(gpios, "-gpios", "#gpio-cells") @@ -1244,6 +1331,19 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_power_domains, }, { .parse_prop = parse_hwlocks, }, { .parse_prop = parse_extcon, }, + { .parse_prop = parse_interrupts_extended, }, + { .parse_prop = parse_nvmem_cells, }, + { .parse_prop = parse_phys, }, + { .parse_prop = parse_wakeup_parent, }, + { .parse_prop = parse_pinctrl0, }, + { .parse_prop = parse_pinctrl1, }, + { .parse_prop = parse_pinctrl2, }, + { .parse_prop = parse_pinctrl3, }, + { .parse_prop = parse_pinctrl4, }, + { .parse_prop = parse_pinctrl5, }, + { .parse_prop = parse_pinctrl6, }, + { .parse_prop = parse_pinctrl7, }, + { .parse_prop = parse_pinctrl8, }, { .parse_prop = parse_regulators, }, { .parse_prop = parse_gpio, }, { .parse_prop = parse_gpios, }, diff --git a/drivers/of/unittest-data/tests-address.dtsi b/drivers/of/unittest-data/tests-address.dtsi index 3fe5d3987beb..6604a52bf6cb 100644 --- a/drivers/of/unittest-data/tests-address.dtsi +++ b/drivers/of/unittest-data/tests-address.dtsi @@ -23,13 +23,13 @@ }; bus@80000000 { - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x80000000 0x100000>; - dma-ranges = <0x10000000 0x0 0x40000000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x80000000 0x0 0x100000>; + dma-ranges = <0x1 0x0 0x0 0x20 0x0>; device@1000 { - reg = <0x1000 0x1000>; + reg = <0x0 0x1000 0x0 0x1000>; }; }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 398de04fd19c..9b7e84bdc7d4 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -900,7 +900,7 @@ static void __init of_unittest_parse_dma_ranges(void) of_unittest_dma_ranges_one("/testcase-data/address-tests/device@70000000", 0x0, 0x20000000, 0x40000000); of_unittest_dma_ranges_one("/testcase-data/address-tests/bus@80000000/device@1000", - 0x10000000, 0x20000000, 0x40000000); + 0x100000000, 0x20000000, 0x2000000000); of_unittest_dma_ranges_one("/testcase-data/address-tests/pci@90000000", 0x80000000, 0x20000000, 0x10000000); } |