From 611cad720148c899db5a383c1c676fd820df7023 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 15 Aug 2011 15:28:14 +0800 Subject: dt: add of_alias_scan and of_alias_get_id The patch adds function of_alias_scan to populate a global lookup table with the properties of 'aliases' node and function of_alias_get_id for drivers to find alias id from the lookup table. v3: Split out automatic addition of aliases on id lookup so that it can be debated separately from the core functionality. v2: - Add of_chosen/of_aliases populating and of_alias_scan() invocation for OF_PROMTREE. - Add locking - rework parse loop Signed-off-by: Shawn Guo Acked-by: David S. Miller Signed-off-by: Grant Likely --- drivers/of/base.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/fdt.c | 6 +-- drivers/of/pdt.c | 8 ++++ 3 files changed, 131 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 3ff22e32b602..8abde58cbe82 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -17,14 +17,39 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include #include #include #include #include +/** + * struct alias_prop - Alias property in 'aliases' node + * @link: List node to link the structure in aliases_lookup list + * @alias: Alias property name + * @np: Pointer to device_node that the alias stands for + * @id: Index value from end of alias name + * @stem: Alias string without the index + * + * The structure represents one alias property of 'aliases' node as + * an entry in aliases_lookup list. + */ +struct alias_prop { + struct list_head link; + const char *alias; + struct device_node *np; + int id; + char stem[0]; +}; + +static LIST_HEAD(aliases_lookup); + struct device_node *allnodes; struct device_node *of_chosen; +struct device_node *of_aliases; + +static DEFINE_MUTEX(of_aliases_mutex); /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. @@ -988,3 +1013,99 @@ out_unlock: } #endif /* defined(CONFIG_OF_DYNAMIC) */ +static void of_alias_add(struct alias_prop *ap, struct device_node *np, + int id, const char *stem, int stem_len) +{ + ap->np = np; + ap->id = id; + strncpy(ap->stem, stem, stem_len); + ap->stem[stem_len] = 0; + list_add_tail(&ap->link, &aliases_lookup); + pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n", + ap->alias, ap->stem, ap->id, np ? np->full_name : NULL); +} + +/** + * of_alias_scan - Scan all properties of 'aliases' node + * + * The function scans all the properties of 'aliases' node and populate + * the the global lookup table with the properties. It returns the + * number of alias_prop found, or error code in error case. + * + * @dt_alloc: An allocator that provides a virtual address to memory + * for the resulting tree + */ +void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) +{ + struct property *pp; + + of_chosen = of_find_node_by_path("/chosen"); + if (of_chosen == NULL) + of_chosen = of_find_node_by_path("/chosen@0"); + of_aliases = of_find_node_by_path("/aliases"); + if (!of_aliases) + return; + + for_each_property(pp, of_aliases->properties) { + const char *start = pp->name; + const char *end = start + strlen(start); + struct device_node *np; + struct alias_prop *ap; + int id, len; + + /* Skip those we do not want to proceed */ + if (!strcmp(pp->name, "name") || + !strcmp(pp->name, "phandle") || + !strcmp(pp->name, "linux,phandle")) + continue; + + np = of_find_node_by_path(pp->value); + if (!np) + continue; + + /* walk the alias backwards to extract the id and work out + * the 'stem' string */ + while (isdigit(*(end-1)) && end > start) + end--; + len = end - start; + + if (kstrtoint(end, 10, &id) < 0) + continue; + + /* Allocate an alias_prop with enough space for the stem */ + ap = dt_alloc(sizeof(*ap) + len + 1, 4); + if (!ap) + continue; + ap->alias = start; + of_alias_add(ap, np, id, start, len); + } +} + +/** + * of_alias_get_id - Get alias id for the given device_node + * @np: Pointer to the given device_node + * @stem: Alias stem of the given device_node + * + * The function travels the lookup table to get alias id for the given + * device_node and alias stem. It returns the alias id if find it. + */ +int of_alias_get_id(struct device_node *np, const char *stem) +{ + struct alias_prop *app; + int id = -ENODEV; + + mutex_lock(&of_aliases_mutex); + list_for_each_entry(app, &aliases_lookup, link) { + if (strcmp(app->stem, stem) != 0) + continue; + + if (np == app->np) { + id = app->id; + break; + } + } + mutex_unlock(&of_aliases_mutex); + + return id; +} +EXPORT_SYMBOL_GPL(of_alias_get_id); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 65200af29c52..aeec35bc3789 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -707,10 +707,8 @@ void __init unflatten_device_tree(void) __unflatten_device_tree(initial_boot_params, &allnodes, early_init_dt_alloc_memory_arch); - /* Get pointer to OF "/chosen" node for use everywhere */ - of_chosen = of_find_node_by_path("/chosen"); - if (of_chosen == NULL) - of_chosen = of_find_node_by_path("/chosen@0"); + /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ + of_alias_scan(early_init_dt_alloc_memory_arch); } #endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 4d87b5dc9284..bc5b3990f6ed 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -229,6 +229,11 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent, return ret; } +static void *kernel_tree_alloc(u64 size, u64 align) +{ + return prom_early_alloc(size); +} + void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) { struct device_node **nextp; @@ -245,4 +250,7 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) nextp = &allnodes->allnext; allnodes->child = of_pdt_build_tree(allnodes, of_pdt_prom_ops->getchild(allnodes->phandle), &nextp); + + /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ + of_alias_scan(kernel_tree_alloc); } -- cgit v1.2.3 From ff05967a07225ab675f6e03eb2d9c155d8c8671c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 22 Sep 2011 14:48:13 +0800 Subject: serial/imx: add of_alias_get_id() reference back As of_alias_get_id() gets fixed and ready for use, the patch adds the of_alias_get_id() reference back to imx serial driver. Signed-off-by: Shawn Guo [grant.likely: changed pr_err() to dev_err(), dropped unnecessary else] Signed-off-by: Grant Likely --- drivers/tty/serial/imx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7e91b3d368cd..99898773706c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1286,17 +1286,20 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe_dt(struct imx_port *sport, struct platform_device *pdev) { - static int portnum = 0; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(imx_uart_dt_ids, &pdev->dev); + int ret; if (!np) return -ENODEV; - sport->port.line = portnum++; - if (sport->port.line >= UART_NR) - return -EINVAL; + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return -ENODEV; + } + sport->port.line = ret; if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; -- cgit v1.2.3 From 85888069cf5d0f21312e3ee730458a5e3a553509 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 3 Aug 2011 10:11:43 +0100 Subject: tty: use of_match_ptr() for of_match_table entry Use the new of_match_ptr() macro for the of_match_table pointer entry to avoid having to #dfine match NULL Signed-off-by: Ben Dooks Signed-off-by: Grant Likely --- drivers/tty/serial/altera_jtaguart.c | 4 +--- drivers/tty/serial/altera_uart.c | 4 +--- drivers/tty/serial/uartlite.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 60e049b041a7..207520069256 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -472,8 +472,6 @@ static struct of_device_id altera_jtaguart_match[] = { {}, }; MODULE_DEVICE_TABLE(of, altera_jtaguart_match); -#else -#define altera_jtaguart_match NULL #endif /* CONFIG_OF */ static struct platform_driver altera_jtaguart_platform_driver = { @@ -482,7 +480,7 @@ static struct platform_driver altera_jtaguart_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, - .of_match_table = altera_jtaguart_match, + .of_match_table = of_match_ptr(altera_jtaguart_match), }, }; diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 50bc5a5ac653..0abd31d2361b 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -616,8 +616,6 @@ static struct of_device_id altera_uart_match[] = { {}, }; MODULE_DEVICE_TABLE(of, altera_uart_match); -#else -#define altera_uart_match NULL #endif /* CONFIG_OF */ static struct platform_driver altera_uart_platform_driver = { @@ -626,7 +624,7 @@ static struct platform_driver altera_uart_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, - .of_match_table = altera_uart_match, + .of_match_table = of_match_ptr(altera_uart_match), }, }; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 8af1ed83a4c0..0aed022d21b7 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -568,8 +568,6 @@ static struct of_device_id ulite_of_match[] __devinitdata = { {} }; MODULE_DEVICE_TABLE(of, ulite_of_match); -#else /* CONFIG_OF */ -#define ulite_of_match NULL #endif /* CONFIG_OF */ static int __devinit ulite_probe(struct platform_device *pdev) @@ -609,7 +607,7 @@ static struct platform_driver ulite_platform_driver = { .driver = { .owner = THIS_MODULE, .name = "uartlite", - .of_match_table = ulite_of_match, + .of_match_table = of_match_ptr(ulite_of_match), }, }; -- cgit v1.2.3 From 4cd7f7a31178ff8a15ad2bc1258b9b2bf2cf51a4 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 14 Sep 2011 20:49:59 +0100 Subject: dt: add helper to read 64-bit integers Add a helper similar to of_property_read_u32() that handles 64-bit integers. v2/v3: constify device node and property name parameters. Cc: Grant Likely Reviewed-by: Rob Herring Signed-off-by: Jamie Iles Signed-off-by: Grant Likely --- drivers/of/base.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 8abde58cbe82..b970562e0111 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -656,6 +656,35 @@ int of_property_read_u32_array(const struct device_node *np, } EXPORT_SYMBOL_GPL(of_property_read_u32_array); +/** + * of_property_read_u64 - Find and read a 64 bit integer from a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * + * Search for a property in a device node and read a 64-bit value from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid u64 value can be decoded. + */ +int of_property_read_u64(const struct device_node *np, const char *propname, + u64 *out_value) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (sizeof(*out_value) > prop->length) + return -EOVERFLOW; + *out_value = of_read_number(prop->value, 2); + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u64); + /** * of_property_read_string - Find and read a string from a property * @np: device node from which the property value is to be read. -- cgit v1.2.3 From dc9372808412edbc653a675a526c2ee6c0c14a91 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 20 Sep 2011 13:02:54 -0500 Subject: of/irq: of_irq_find_parent: check for parent equal to child An interrupt controller may often implicitly inherit itself from a parent node when in fact the controller is the interrupt root controller. Guard against the case of child == parent and return NULL in this case. This can also be fixed by adding an explicit "interrupt-parent;" to a root interrupt controller node. Based on code from Grant Likely. Signed-off-by: Rob Herring Cc: Grant Likely --- drivers/of/irq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 9f689f1da0fc..6a5b5e777dd2 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -58,27 +58,27 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); */ struct device_node *of_irq_find_parent(struct device_node *child) { - struct device_node *p; + struct device_node *p, *c = child; const __be32 *parp; - if (!of_node_get(child)) + if (!of_node_get(c)) return NULL; do { - parp = of_get_property(child, "interrupt-parent", NULL); + parp = of_get_property(c, "interrupt-parent", NULL); if (parp == NULL) - p = of_get_parent(child); + p = of_get_parent(c); else { if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) p = of_node_get(of_irq_dflt_pic); else p = of_find_node_by_phandle(be32_to_cpup(parp)); } - of_node_put(child); - child = p; + of_node_put(c); + c = p; } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); - return p; + return (p == child) ? NULL : p; } /** -- cgit v1.2.3 From 6b3754d6183797263bc6b28884323cf7842a8961 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 5 Oct 2011 11:18:40 -0600 Subject: devicetree: fix build error on drivers/tty/serial/altera_jtaguart.c This patch fixes the following build error caused by commit 85888069cf5d ("tty: use of_match_ptr() for of_match_table entry"). The problem was a missing #include which is where of_match_ptr() is defined. drivers/tty/serial/altera_jtaguart.c:483:3: error: implicit declaration of function 'of_match_ptr' [-Werror=implicit-function-declaration] drivers/tty/serial/altera_jtaguart.c:483:34: error: 'altera_jtaguart_match' undeclared here (not in a function) Signed-off-by: Grant Likely Cc: Ben Dooks Cc: Tobias Klauser (maintainer:ALTERA UART/JTAG...) Cc: Alan Cox (maintainer:SERIAL DRIVERS) --- drivers/tty/serial/altera_jtaguart.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 207520069256..af46c56080db 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From ae97159aed6eff68f4ac86472b018985f071fed5 Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Thu, 20 Oct 2011 17:00:09 -0400 Subject: of_mdio: Don't phy_scan_fixups() twice The "phy_device_register()" call 5 lines down already calls phy_scan_fixups(), there's no need to do it a second time. Signed-off-by: Kyle Moffett Signed-off-by: Grant Likely --- drivers/of/of_mdio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index d35e300b0ad1..980c079e4443 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -83,7 +83,6 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) addr); continue; } - phy_scan_fixups(phy); /* Associate the OF node with the device structure so it * can be looked up later */ -- cgit v1.2.3