aboutsummaryrefslogtreecommitdiff
path: root/drivers/of
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/address.c29
-rw-r--r--drivers/of/of_mdio.c4
-rw-r--r--drivers/of/of_reserved_mem.c14
-rw-r--r--drivers/of/property.c112
-rw-r--r--drivers/of/unittest-data/tests-address.dtsi10
-rw-r--r--drivers/of/unittest.c2
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);
}