* [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id
2011-06-24 18:04 [PATCH v2 0/5] Add basic device support for imx51 babbage Shawn Guo
@ 2011-06-24 18:04 ` Shawn Guo
2011-07-08 9:36 ` Shawn Guo
2011-07-15 2:53 ` Grant Likely
2011-06-24 18:04 ` [PATCH v2 2/5] serial/imx: get rid of the use of cpu_is_mx1() Shawn Guo
` (3 subsequent siblings)
4 siblings, 2 replies; 9+ messages in thread
From: Shawn Guo @ 2011-06-24 18:04 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
drivers/of/base.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/of/fdt.c | 6 ++
include/linux/of.h | 7 ++
3 files changed, 194 insertions(+), 0 deletions(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 632ebae..89efd10 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -17,14 +17,38 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/bootmem.h>
+#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
+/**
+ * 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
+ * @alias_id: Alias id decoded from alias
+ * @alias_stem: Alias stem name decoded from alias
+ *
+ * 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 alias_id;
+ char alias_stem[0];
+};
+
+static LIST_HEAD(aliases_lookup);
+
struct device_node *allnodes;
struct device_node *of_chosen;
+struct device_node *of_aliases;
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
@@ -922,3 +946,160 @@ out_unlock:
}
#endif /* defined(CONFIG_OF_DYNAMIC) */
+/*
+ * of_alias_find_available_id - Find an available 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 find an available id for the
+ * given device_node with given alias stem. It returns the id found.
+ */
+static int of_alias_find_available_id(struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = 0;
+
+ while (1) {
+ bool used = false;
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (!strcmp(app->alias_stem, stem) &&
+ app->alias_id == id) {
+ used = true;
+ break;
+ }
+ }
+
+ if (used)
+ id++;
+ else
+ return id;
+ }
+}
+
+/**
+ * of_alias_lookup_add - Add alias into lookup table
+ * @alias: Alias name
+ * @id: Alias id
+ * @stem: Alias stem name
+ * @np: Pointer to device_node
+ *
+ * The function adds one alias into the lookup table and populate it
+ * with the info passed in. It returns 0 in sucess, or error code.
+ */
+static int of_alias_lookup_add(char *alias, int id, const char *stem,
+ struct device_node *np)
+{
+ struct alias_prop *app;
+ size_t sz = sizeof(*app) + strlen(stem) + 1;
+
+ app = kzalloc(sz, GFP_KERNEL);
+ if (!app) {
+ /*
+ * It may fail due to being called by boot code,
+ * so try alloc_bootmem before return error.
+ */
+ app = alloc_bootmem(sz);
+ if (!app)
+ return -ENOMEM;
+ }
+
+ app->np = np;
+ app->alias = alias;
+ app->alias_id = id;
+ strcpy(app->alias_stem, stem);
+ list_add_tail(&app->link, &aliases_lookup);
+
+ return 0;
+}
+
+/**
+ * of_alias_decode - Decode alias stem and id from alias name
+ * @alias: Alias name to be decoded
+ * @stem: Pointer used to return stem name
+ *
+ * The function decodes alias stem name and alias id from the given
+ * alias name. It returns stem name via parameter 'stem', and stem id
+ * via the return value. If no id is found in alias name, it returns 0
+ * as the default.
+ */
+static int of_alias_decode(char *alias, char *stem)
+{
+ int len = strlen(alias);
+ char *end = alias + len;
+
+ while (isdigit(*--end))
+ len--;
+
+ strncpy(stem, alias, len);
+ stem[len] = '\0';
+
+ return strlen(++end) ? simple_strtoul(end, NULL, 10) : 0;
+}
+
+/**
+ * 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.
+ */
+int of_alias_scan(void)
+{
+ struct property *pp;
+ int ret, num = 0;
+
+ if (!of_aliases)
+ return -ENODEV;
+
+ for_each_property(pp, of_aliases->properties) {
+ char stem[32];
+ int id = of_alias_decode(pp->name, stem);
+
+ /* Skip those we do not want to proceed */
+ if (!strcmp(pp->name, "name") ||
+ !strcmp(pp->name, "phandle") ||
+ !strcmp(pp->name, "linux,phandle"))
+ continue;
+
+ ret = of_alias_lookup_add(pp->name, id, stem,
+ of_find_node_by_path(pp->value));
+ if (ret < 0)
+ return ret;
+ else
+ num++;
+ }
+
+ return num;
+}
+
+/**
+ * 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.
+ * If not, dynamically creates one in the lookup table and returns it,
+ * or returns error code if fail to create.
+ */
+int of_alias_get_id(struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = -1;
+
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (np == app->np) {
+ id = app->alias_id;
+ break;
+ }
+ }
+
+ if (id == -1) {
+ id = of_alias_find_available_id(np, stem);
+ if (of_alias_lookup_add(NULL, id, stem, np) < 0)
+ return -ENODEV;
+ }
+
+ return id;
+}
+EXPORT_SYMBOL_GPL(of_alias_get_id);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 65200af..998dc63 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -711,6 +711,12 @@ void __init unflatten_device_tree(void)
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen at 0");
+
+ of_aliases = of_find_node_by_path("/aliases");
+ if (of_aliases == NULL)
+ of_aliases = of_find_node_by_path("/aliases@0");
+
+ of_alias_scan();
}
#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/include/linux/of.h b/include/linux/of.h
index bfc0ed1..c35cc47 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -68,6 +68,7 @@ struct device_node {
/* Pointer for first entry in chain of all nodes. */
extern struct device_node *allnodes;
extern struct device_node *of_chosen;
+extern struct device_node *of_aliases;
extern rwlock_t devtree_lock;
static inline bool of_have_populated_dt(void)
@@ -201,6 +202,9 @@ extern int of_device_is_available(const struct device_node *device);
extern const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp);
+#define for_each_property(pp, properties) \
+ for (pp = properties; pp != NULL; pp = pp->next)
+
extern int of_n_addr_cells(struct device_node *np);
extern int of_n_size_cells(struct device_node *np);
extern const struct of_device_id *of_match_node(
@@ -213,6 +217,9 @@ extern int of_parse_phandles_with_args(struct device_node *np,
const char *list_name, const char *cells_name, int index,
struct device_node **out_node, const void **out_args);
+extern int of_alias_scan(void);
+extern int of_alias_get_id(struct device_node *np, const char *stem);
+
extern int of_machine_is_compatible(const char *compat);
extern int prom_add_property(struct device_node* np, struct property* prop);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id
2011-06-24 18:04 ` [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id Shawn Guo
@ 2011-07-08 9:36 ` Shawn Guo
2011-07-15 2:53 ` Grant Likely
1 sibling, 0 replies; 9+ messages in thread
From: Shawn Guo @ 2011-07-08 9:36 UTC (permalink / raw)
To: linux-arm-kernel
Hi Grant,
I saw neither your comments nor ack on this patch. Where does it go?
Regards,
Shawn
On Sat, Jun 25, 2011 at 02:04:32AM +0800, Shawn Guo wrote:
> 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.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> ---
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id
2011-06-24 18:04 ` [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id Shawn Guo
2011-07-08 9:36 ` Shawn Guo
@ 2011-07-15 2:53 ` Grant Likely
2011-07-15 15:24 ` Shawn Guo
1 sibling, 1 reply; 9+ messages in thread
From: Grant Likely @ 2011-07-15 2:53 UTC (permalink / raw)
To: linux-arm-kernel
On Sat, Jun 25, 2011 at 02:04:32AM +0800, Shawn Guo wrote:
> 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.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
Hey Shawn,
Comments below, but I've gone ahead and fixed them because I'm keen to
get this patch merged. I just wanted to let you know what I changed.
I'll post the modified version so you can test it.
> ---
> drivers/of/base.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> drivers/of/fdt.c | 6 ++
> include/linux/of.h | 7 ++
> 3 files changed, 194 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index 632ebae..89efd10 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -17,14 +17,38 @@
> * as published by the Free Software Foundation; either version
> * 2 of the License, or (at your option) any later version.
> */
> +#include <linux/bootmem.h>
> +#include <linux/ctype.h>
> #include <linux/module.h>
> #include <linux/of.h>
> #include <linux/spinlock.h>
> #include <linux/slab.h>
> #include <linux/proc_fs.h>
>
> +/**
> + * 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
> + * @alias_id: Alias id decoded from alias
> + * @alias_stem: Alias stem name decoded from alias
> + *
> + * 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 alias_id;
> + char alias_stem[0];
> +};
> +
> +static LIST_HEAD(aliases_lookup);
> +
> struct device_node *allnodes;
> struct device_node *of_chosen;
> +struct device_node *of_aliases;
>
> /* use when traversing tree through the allnext, child, sibling,
> * or parent members of struct device_node.
> @@ -922,3 +946,160 @@ out_unlock:
> }
> #endif /* defined(CONFIG_OF_DYNAMIC) */
>
> +/*
> + * of_alias_find_available_id - Find an available id for the given device_node
Nit: kerneldoc format is "/**" to start the comment, and function
names should have '()' on it.
> + * @np: Pointer to the given device_node
> + * @stem: Alias stem of the given device_node
> + *
> + * The function travels the lookup table to find an available id for the
> + * given device_node with given alias stem. It returns the id found.
> + */
> +static int of_alias_find_available_id(struct device_node *np, const char *stem)
> +{
> + struct alias_prop *app;
> + int id = 0;
> +
> + while (1) {
> + bool used = false;
> + list_for_each_entry(app, &aliases_lookup, link) {
> + if (!strcmp(app->alias_stem, stem) &&
> + app->alias_id == id) {
> + used = true;
> + break;
> + }
> + }
> +
> + if (used)
> + id++;
> + else
> + return id;
> + }
> +}
I've simplified this somewhat to do the list_for_each_entry() only
once, and to bump up the id to +1 the largest entry:
list_for_each_entry(app, &aliases_lookup, link)
if ((strcmp(app->stem, stem) == 0) && id <= app->id)
id = app->id + 1;
.... actually, after looking further, I've rolled this code into the
of_alias_get_id() function.
> +
> +/**
> + * of_alias_lookup_add - Add alias into lookup table
> + * @alias: Alias name
> + * @id: Alias id
> + * @stem: Alias stem name
> + * @np: Pointer to device_node
> + *
> + * The function adds one alias into the lookup table and populate it
> + * with the info passed in. It returns 0 in sucess, or error code.
> + */
> +static int of_alias_lookup_add(char *alias, int id, const char *stem,
> + struct device_node *np)
> +{
> + struct alias_prop *app;
> + size_t sz = sizeof(*app) + strlen(stem) + 1;
> +
> + app = kzalloc(sz, GFP_KERNEL);
> + if (!app) {
> + /*
> + * It may fail due to being called by boot code,
> + * so try alloc_bootmem before return error.
> + */
> + app = alloc_bootmem(sz);
> + if (!app)
> + return -ENOMEM;
> + }
I'm not too fond of this since we *know* when this is going to be
called from early boot. So, instead, I've changed the code to use the
already existing dt_alloc functions as an argument to of_alias_lookup_add().
Also, alloc_bootmem() doesn't work on all platforms.
early_init_dt_alloc_memory_arch() needs to be used instead.
> +
> + app->np = np;
> + app->alias = alias;
> + app->alias_id = id;
> + strcpy(app->alias_stem, stem);
> + list_add_tail(&app->link, &aliases_lookup);
> +
> + return 0;
> +}
> +
> +/**
> + * of_alias_decode - Decode alias stem and id from alias name
> + * @alias: Alias name to be decoded
> + * @stem: Pointer used to return stem name
> + *
> + * The function decodes alias stem name and alias id from the given
> + * alias name. It returns stem name via parameter 'stem', and stem id
> + * via the return value. If no id is found in alias name, it returns 0
> + * as the default.
> + */
> +static int of_alias_decode(char *alias, char *stem)
> +{
> + int len = strlen(alias);
> + char *end = alias + len;
> +
> + while (isdigit(*--end))
> + len--;
Need to protect against len < 0
> +
> + strncpy(stem, alias, len);
> + stem[len] = '\0';
> +
> + return strlen(++end) ? simple_strtoul(end, NULL, 10) : 0;
> +}
> +
> +/**
> + * 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.
> + */
> +int of_alias_scan(void)
Changed to '__init void of_aliases_scan(void)'. There is no point in
returning an error code since it is never checked, and there is no
point in bailing on an error just in case it is a problem with only
one alias.
> +{
> + struct property *pp;
> + int ret, num = 0;
> +
> + if (!of_aliases)
> + return -ENODEV;
> +
> + for_each_property(pp, of_aliases->properties) {
> + char stem[32];
> + int id = of_alias_decode(pp->name, stem);
> +
> + /* Skip those we do not want to proceed */
> + if (!strcmp(pp->name, "name") ||
> + !strcmp(pp->name, "phandle") ||
> + !strcmp(pp->name, "linux,phandle"))
> + continue;
> +
> + ret = of_alias_lookup_add(pp->name, id, stem,
> + of_find_node_by_path(pp->value));
> + if (ret < 0)
> + return ret;
> + else
> + num++;
> + }
> +
> + return num;
> +}
> +
> +/**
> + * 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.
> + * If not, dynamically creates one in the lookup table and returns it,
> + * or returns error code if fail to create.
> + */
> +int of_alias_get_id(struct device_node *np, const char *stem)
> +{
> + struct alias_prop *app;
> + int id = -1;
> +
> + list_for_each_entry(app, &aliases_lookup, link) {
> + if (np == app->np) {
> + id = app->alias_id;
> + break;
> + }
> + }
> +
> + if (id == -1) {
> + id = of_alias_find_available_id(np, stem);
> + if (of_alias_lookup_add(NULL, id, stem, np) < 0)
> + return -ENODEV;
> + }
> +
> + return id;
> +}
This whole function needs to be protected by a mutex.
> +EXPORT_SYMBOL_GPL(of_alias_get_id);
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index 65200af..998dc63 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -711,6 +711,12 @@ void __init unflatten_device_tree(void)
> of_chosen = of_find_node_by_path("/chosen");
> if (of_chosen == NULL)
> of_chosen = of_find_node_by_path("/chosen at 0");
> +
> + of_aliases = of_find_node_by_path("/aliases");
> + if (of_aliases == NULL)
> + of_aliases = of_find_node_by_path("/aliases at 0");
I don't think the /aliases at 0 variant is necessary. I've dropped it.
g.
> +
> + of_alias_scan();
> }
>
> #endif /* CONFIG_OF_EARLY_FLATTREE */
> diff --git a/include/linux/of.h b/include/linux/of.h
> index bfc0ed1..c35cc47 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -68,6 +68,7 @@ struct device_node {
> /* Pointer for first entry in chain of all nodes. */
> extern struct device_node *allnodes;
> extern struct device_node *of_chosen;
> +extern struct device_node *of_aliases;
> extern rwlock_t devtree_lock;
>
> static inline bool of_have_populated_dt(void)
> @@ -201,6 +202,9 @@ extern int of_device_is_available(const struct device_node *device);
> extern const void *of_get_property(const struct device_node *node,
> const char *name,
> int *lenp);
> +#define for_each_property(pp, properties) \
> + for (pp = properties; pp != NULL; pp = pp->next)
> +
> extern int of_n_addr_cells(struct device_node *np);
> extern int of_n_size_cells(struct device_node *np);
> extern const struct of_device_id *of_match_node(
> @@ -213,6 +217,9 @@ extern int of_parse_phandles_with_args(struct device_node *np,
> const char *list_name, const char *cells_name, int index,
> struct device_node **out_node, const void **out_args);
>
> +extern int of_alias_scan(void);
> +extern int of_alias_get_id(struct device_node *np, const char *stem);
> +
> extern int of_machine_is_compatible(const char *compat);
>
> extern int prom_add_property(struct device_node* np, struct property* prop);
> --
> 1.7.4.1
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id
2011-07-15 2:53 ` Grant Likely
@ 2011-07-15 15:24 ` Shawn Guo
0 siblings, 0 replies; 9+ messages in thread
From: Shawn Guo @ 2011-07-15 15:24 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Jul 14, 2011 at 08:53:20PM -0600, Grant Likely wrote:
> On Sat, Jun 25, 2011 at 02:04:32AM +0800, Shawn Guo wrote:
> > 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.
> >
> > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > Cc: Grant Likely <grant.likely@secretlab.ca>
>
> Hey Shawn,
>
> Comments below, but I've gone ahead and fixed them because I'm keen to
> get this patch merged. I just wanted to let you know what I changed.
> I'll post the modified version so you can test it.
>
Thanks for doing this. It makes the wheel spin fast. I respect
changes you made, and will give it a test once you post it.
Regards,
Shawn
> > ---
> > drivers/of/base.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > drivers/of/fdt.c | 6 ++
> > include/linux/of.h | 7 ++
> > 3 files changed, 194 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/of/base.c b/drivers/of/base.c
> > index 632ebae..89efd10 100644
> > --- a/drivers/of/base.c
> > +++ b/drivers/of/base.c
> > @@ -17,14 +17,38 @@
> > * as published by the Free Software Foundation; either version
> > * 2 of the License, or (at your option) any later version.
> > */
> > +#include <linux/bootmem.h>
> > +#include <linux/ctype.h>
> > #include <linux/module.h>
> > #include <linux/of.h>
> > #include <linux/spinlock.h>
> > #include <linux/slab.h>
> > #include <linux/proc_fs.h>
> >
> > +/**
> > + * 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
> > + * @alias_id: Alias id decoded from alias
> > + * @alias_stem: Alias stem name decoded from alias
> > + *
> > + * 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 alias_id;
> > + char alias_stem[0];
> > +};
> > +
> > +static LIST_HEAD(aliases_lookup);
> > +
> > struct device_node *allnodes;
> > struct device_node *of_chosen;
> > +struct device_node *of_aliases;
> >
> > /* use when traversing tree through the allnext, child, sibling,
> > * or parent members of struct device_node.
> > @@ -922,3 +946,160 @@ out_unlock:
> > }
> > #endif /* defined(CONFIG_OF_DYNAMIC) */
> >
> > +/*
> > + * of_alias_find_available_id - Find an available id for the given device_node
>
> Nit: kerneldoc format is "/**" to start the comment, and function
> names should have '()' on it.
>
> > + * @np: Pointer to the given device_node
> > + * @stem: Alias stem of the given device_node
> > + *
> > + * The function travels the lookup table to find an available id for the
> > + * given device_node with given alias stem. It returns the id found.
> > + */
> > +static int of_alias_find_available_id(struct device_node *np, const char *stem)
> > +{
> > + struct alias_prop *app;
> > + int id = 0;
> > +
> > + while (1) {
> > + bool used = false;
> > + list_for_each_entry(app, &aliases_lookup, link) {
> > + if (!strcmp(app->alias_stem, stem) &&
> > + app->alias_id == id) {
> > + used = true;
> > + break;
> > + }
> > + }
> > +
> > + if (used)
> > + id++;
> > + else
> > + return id;
> > + }
> > +}
>
> I've simplified this somewhat to do the list_for_each_entry() only
> once, and to bump up the id to +1 the largest entry:
>
> list_for_each_entry(app, &aliases_lookup, link)
> if ((strcmp(app->stem, stem) == 0) && id <= app->id)
> id = app->id + 1;
>
> .... actually, after looking further, I've rolled this code into the
> of_alias_get_id() function.
>
> > +
> > +/**
> > + * of_alias_lookup_add - Add alias into lookup table
> > + * @alias: Alias name
> > + * @id: Alias id
> > + * @stem: Alias stem name
> > + * @np: Pointer to device_node
> > + *
> > + * The function adds one alias into the lookup table and populate it
> > + * with the info passed in. It returns 0 in sucess, or error code.
> > + */
> > +static int of_alias_lookup_add(char *alias, int id, const char *stem,
> > + struct device_node *np)
> > +{
> > + struct alias_prop *app;
> > + size_t sz = sizeof(*app) + strlen(stem) + 1;
> > +
> > + app = kzalloc(sz, GFP_KERNEL);
> > + if (!app) {
> > + /*
> > + * It may fail due to being called by boot code,
> > + * so try alloc_bootmem before return error.
> > + */
> > + app = alloc_bootmem(sz);
> > + if (!app)
> > + return -ENOMEM;
> > + }
>
> I'm not too fond of this since we *know* when this is going to be
> called from early boot. So, instead, I've changed the code to use the
> already existing dt_alloc functions as an argument to of_alias_lookup_add().
>
> Also, alloc_bootmem() doesn't work on all platforms.
> early_init_dt_alloc_memory_arch() needs to be used instead.
>
>
> > +
> > + app->np = np;
> > + app->alias = alias;
> > + app->alias_id = id;
> > + strcpy(app->alias_stem, stem);
> > + list_add_tail(&app->link, &aliases_lookup);
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * of_alias_decode - Decode alias stem and id from alias name
> > + * @alias: Alias name to be decoded
> > + * @stem: Pointer used to return stem name
> > + *
> > + * The function decodes alias stem name and alias id from the given
> > + * alias name. It returns stem name via parameter 'stem', and stem id
> > + * via the return value. If no id is found in alias name, it returns 0
> > + * as the default.
> > + */
> > +static int of_alias_decode(char *alias, char *stem)
> > +{
> > + int len = strlen(alias);
> > + char *end = alias + len;
> > +
> > + while (isdigit(*--end))
> > + len--;
>
> Need to protect against len < 0
>
> > +
> > + strncpy(stem, alias, len);
> > + stem[len] = '\0';
> > +
> > + return strlen(++end) ? simple_strtoul(end, NULL, 10) : 0;
> > +}
> > +
> > +/**
> > + * 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.
> > + */
> > +int of_alias_scan(void)
>
> Changed to '__init void of_aliases_scan(void)'. There is no point in
> returning an error code since it is never checked, and there is no
> point in bailing on an error just in case it is a problem with only
> one alias.
>
> > +{
> > + struct property *pp;
> > + int ret, num = 0;
> > +
> > + if (!of_aliases)
> > + return -ENODEV;
> > +
> > + for_each_property(pp, of_aliases->properties) {
> > + char stem[32];
> > + int id = of_alias_decode(pp->name, stem);
> > +
> > + /* Skip those we do not want to proceed */
> > + if (!strcmp(pp->name, "name") ||
> > + !strcmp(pp->name, "phandle") ||
> > + !strcmp(pp->name, "linux,phandle"))
> > + continue;
> > +
> > + ret = of_alias_lookup_add(pp->name, id, stem,
> > + of_find_node_by_path(pp->value));
> > + if (ret < 0)
> > + return ret;
> > + else
> > + num++;
> > + }
> > +
> > + return num;
> > +}
> > +
> > +/**
> > + * 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.
> > + * If not, dynamically creates one in the lookup table and returns it,
> > + * or returns error code if fail to create.
> > + */
> > +int of_alias_get_id(struct device_node *np, const char *stem)
> > +{
> > + struct alias_prop *app;
> > + int id = -1;
> > +
> > + list_for_each_entry(app, &aliases_lookup, link) {
> > + if (np == app->np) {
> > + id = app->alias_id;
> > + break;
> > + }
> > + }
> > +
> > + if (id == -1) {
> > + id = of_alias_find_available_id(np, stem);
> > + if (of_alias_lookup_add(NULL, id, stem, np) < 0)
> > + return -ENODEV;
> > + }
> > +
> > + return id;
> > +}
>
> This whole function needs to be protected by a mutex.
>
> > +EXPORT_SYMBOL_GPL(of_alias_get_id);
> > diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> > index 65200af..998dc63 100644
> > --- a/drivers/of/fdt.c
> > +++ b/drivers/of/fdt.c
> > @@ -711,6 +711,12 @@ void __init unflatten_device_tree(void)
> > of_chosen = of_find_node_by_path("/chosen");
> > if (of_chosen == NULL)
> > of_chosen = of_find_node_by_path("/chosen at 0");
> > +
> > + of_aliases = of_find_node_by_path("/aliases");
> > + if (of_aliases == NULL)
> > + of_aliases = of_find_node_by_path("/aliases at 0");
>
> I don't think the /aliases at 0 variant is necessary. I've dropped it.
>
> g.
>
> > +
> > + of_alias_scan();
> > }
> >
> > #endif /* CONFIG_OF_EARLY_FLATTREE */
> > diff --git a/include/linux/of.h b/include/linux/of.h
> > index bfc0ed1..c35cc47 100644
> > --- a/include/linux/of.h
> > +++ b/include/linux/of.h
> > @@ -68,6 +68,7 @@ struct device_node {
> > /* Pointer for first entry in chain of all nodes. */
> > extern struct device_node *allnodes;
> > extern struct device_node *of_chosen;
> > +extern struct device_node *of_aliases;
> > extern rwlock_t devtree_lock;
> >
> > static inline bool of_have_populated_dt(void)
> > @@ -201,6 +202,9 @@ extern int of_device_is_available(const struct device_node *device);
> > extern const void *of_get_property(const struct device_node *node,
> > const char *name,
> > int *lenp);
> > +#define for_each_property(pp, properties) \
> > + for (pp = properties; pp != NULL; pp = pp->next)
> > +
> > extern int of_n_addr_cells(struct device_node *np);
> > extern int of_n_size_cells(struct device_node *np);
> > extern const struct of_device_id *of_match_node(
> > @@ -213,6 +217,9 @@ extern int of_parse_phandles_with_args(struct device_node *np,
> > const char *list_name, const char *cells_name, int index,
> > struct device_node **out_node, const void **out_args);
> >
> > +extern int of_alias_scan(void);
> > +extern int of_alias_get_id(struct device_node *np, const char *stem);
> > +
> > extern int of_machine_is_compatible(const char *compat);
> >
> > extern int prom_add_property(struct device_node* np, struct property* prop);
> > --
> > 1.7.4.1
> >
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/5] serial/imx: get rid of the use of cpu_is_mx1()
2011-06-24 18:04 [PATCH v2 0/5] Add basic device support for imx51 babbage Shawn Guo
2011-06-24 18:04 ` [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id Shawn Guo
@ 2011-06-24 18:04 ` Shawn Guo
2011-06-24 18:04 ` [PATCH v2 3/5] serial/imx: add device tree support Shawn Guo
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Shawn Guo @ 2011-06-24 18:04 UTC (permalink / raw)
To: linux-arm-kernel
The patch removes all the uses of cpu_is_mx1(). Instead, it uses
the .id_table of platform_driver to distinguish the uart device type.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
---
arch/arm/mach-imx/clock-imx1.c | 6 +-
arch/arm/plat-mxc/devices/platform-imx-uart.c | 2 +-
drivers/tty/serial/imx.c | 52 ++++++++++++++++++++++--
3 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-imx/clock-imx1.c b/arch/arm/mach-imx/clock-imx1.c
index dcc4172..4aabeb2 100644
--- a/arch/arm/mach-imx/clock-imx1.c
+++ b/arch/arm/mach-imx/clock-imx1.c
@@ -587,9 +587,9 @@ static struct clk_lookup lookups[] __initdata = {
_REGISTER_CLOCK(NULL, "mma", mma_clk)
_REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk)
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
- _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk)
- _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
- _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
+ _REGISTER_CLOCK("imx1-uart.0", NULL, uart_clk)
+ _REGISTER_CLOCK("imx1-uart.1", NULL, uart_clk)
+ _REGISTER_CLOCK("imx1-uart.2", NULL, uart_clk)
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
_REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
_REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk)
diff --git a/arch/arm/plat-mxc/devices/platform-imx-uart.c b/arch/arm/plat-mxc/devices/platform-imx-uart.c
index 3c854c2..01982a1 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-uart.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-uart.c
@@ -150,7 +150,7 @@ struct platform_device *__init imx_add_imx_uart_3irq(
},
};
- return imx_add_platform_device("imx-uart", data->id, res,
+ return imx_add_platform_device("imx1-uart", data->id, res,
ARRAY_SIZE(res), pdata, sizeof(*pdata));
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a544731..8a6f4e1 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -48,7 +48,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <mach/hardware.h>
#include <mach/imx-uart.h>
/* Register definitions */
@@ -67,7 +66,8 @@
#define UBMR 0xa8 /* BRM Modulator Register */
#define UBRC 0xac /* Baud Rate Count Register */
#define MX2_ONEMS 0xb0 /* One Millisecond register */
-#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
+#define MX1_UTS 0xd0 /* UART Test Register on mx1 */
+#define MX2_UTS 0xb4 /* UART Test Register on mx2 and later */
/* UART Control Register Bit Fields.*/
#define URXD_CHARRDY (1<<15)
@@ -181,6 +181,17 @@
#define UART_NR 8
+enum imx_uart_type {
+ IMX1_UART,
+ IMX2_UART,
+};
+
+/* device type dependent stuff */
+struct imx_uart_data {
+ unsigned uts_reg;
+ unsigned type;
+};
+
struct imx_port {
struct uart_port port;
struct timer_list timer;
@@ -192,6 +203,7 @@ struct imx_port {
unsigned int irda_inv_tx:1;
unsigned short trcv_delay; /* transceiver delay */
struct clk *clk;
+ struct imx_uart_data *devdata;
};
#ifdef CONFIG_IRDA
@@ -200,6 +212,21 @@ struct imx_port {
#define USE_IRDA(sport) (0)
#endif
+static struct imx_uart_data imx_uart_devdata[] = {
+ [IMX1_UART] = {
+ .uts_reg = MX1_UTS,
+ .type = IMX1_UART,
+ },
+ [IMX2_UART] = {
+ .uts_reg = MX2_UTS,
+ .type = IMX2_UART,
+ },
+};
+
+#define UTS (sport->devdata->uts_reg)
+#define IS_IMX1_UART(sport) (sport->devdata->type == IMX1_UART)
+#define IS_IMX2_UART(sport) (sport->devdata->type == IMX2_UART)
+
/*
* Handle any change of modem status signal since we were last called.
*/
@@ -689,7 +716,7 @@ static int imx_startup(struct uart_port *port)
}
}
- if (!cpu_is_mx1()) {
+ if (IS_IMX2_UART(sport)) {
temp = readl(sport->port.membase + UCR3);
temp |= MX2_UCR3_RXDMUXSEL;
writel(temp, sport->port.membase + UCR3);
@@ -923,7 +950,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
writel(num, sport->port.membase + UBIR);
writel(denom, sport->port.membase + UBMR);
- if (!cpu_is_mx1())
+ if (IS_IMX2_UART(sport))
writel(sport->port.uartclk / div / 1000,
sport->port.membase + MX2_ONEMS);
@@ -1063,7 +1090,7 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
old_ucr2 = readl(sport->port.membase + UCR2);
- if (cpu_is_mx1())
+ if (IS_IMX1_UART(sport))
ucr1 |= MX1_UCR1_UARTCLKEN;
ucr1 |= UCR1_UARTEN;
ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
@@ -1263,6 +1290,7 @@ static int serial_imx_probe(struct platform_device *pdev)
init_timer(&sport->timer);
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
+ sport->devdata = &imx_uart_devdata[pdev->id_entry->driver_data];
sport->clk = clk_get(&pdev->dev, "uart");
if (IS_ERR(sport->clk)) {
@@ -1335,12 +1363,26 @@ static int serial_imx_remove(struct platform_device *pdev)
return 0;
}
+static struct platform_device_id imx_uart_devtype[] = {
+ {
+ .name = "imx1-uart",
+ .driver_data = IMX1_UART,
+ }, {
+ .name = "imx-uart",
+ .driver_data = IMX2_UART,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
+
static struct platform_driver serial_imx_driver = {
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.suspend = serial_imx_suspend,
.resume = serial_imx_resume,
+ .id_table = imx_uart_devtype,
.driver = {
.name = "imx-uart",
.owner = THIS_MODULE,
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/5] serial/imx: add device tree support
2011-06-24 18:04 [PATCH v2 0/5] Add basic device support for imx51 babbage Shawn Guo
2011-06-24 18:04 ` [PATCH v2 1/5] dt: add of_alias_scan and of_alias_get_id Shawn Guo
2011-06-24 18:04 ` [PATCH v2 2/5] serial/imx: get rid of the use of cpu_is_mx1() Shawn Guo
@ 2011-06-24 18:04 ` Shawn Guo
2011-06-24 18:04 ` [PATCH v2 4/5] net/fec: " Shawn Guo
2011-06-24 18:04 ` [PATCH v2 5/5] ARM: mx5: add basic device tree support for imx51 babbage Shawn Guo
4 siblings, 0 replies; 9+ messages in thread
From: Shawn Guo @ 2011-06-24 18:04 UTC (permalink / raw)
To: linux-arm-kernel
It adds device tree data parsing support for imx tty/serial driver.
Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
Signed-off-by: Jason Liu <jason.hui@linaro.org>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
---
.../bindings/tty/serial/fsl-imx-uart.txt | 20 +++++
drivers/tty/serial/imx.c | 82 +++++++++++++++++---
2 files changed, 92 insertions(+), 10 deletions(-)
create mode 100644 Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
new file mode 100644
index 0000000..9aafe0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
@@ -0,0 +1,20 @@
+* Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
+
+Required properties:
+- compatible : should be "fsl,<soc>-uart"
+- reg : address and length of the register set for the device
+- interrupts : should contain uart interrupt
+- id : should be the port ID defined by soc
+
+Optional properties:
+- fsl,uart-has-rtscts : indicate the uart has rts and cts
+- fsl,irda-mode : support irda mode
+
+Example:
+
+uart at 73fbc000 {
+ compatible = "fsl,imx51-uart", "fsl,imx21-uart";
+ reg = <0x73fbc000 0x4000>;
+ interrupts = <31>;
+ fsl,uart-has-rtscts;
+};
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 8a6f4e1..bef27b3 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -45,6 +45,8 @@
#include <linux/delay.h>
#include <linux/rational.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -227,6 +229,12 @@ static struct imx_uart_data imx_uart_devdata[] = {
#define IS_IMX1_UART(sport) (sport->devdata->type == IMX1_UART)
#define IS_IMX2_UART(sport) (sport->devdata->type == IMX2_UART)
+static struct of_device_id imx_uart_dt_ids[] = {
+ { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
+ { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX2_UART], },
+ { /* sentinel */ },
+};
+
/*
* Handle any change of modem status signal since we were last called.
*/
@@ -1250,6 +1258,58 @@ static int serial_imx_resume(struct platform_device *dev)
return 0;
}
+#ifdef CONFIG_OF
+static int serial_imx_probe_dt(struct imx_port *sport,
+ struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(imx_uart_dt_ids, &pdev->dev);
+
+ if (!node)
+ return -ENODEV;
+
+ pdev->id = of_alias_get_id(node, "serial");
+ if (pdev->id < 0)
+ return -ENODEV;
+
+ if (of_get_property(node, "fsl,uart-has-rtscts", NULL))
+ sport->have_rtscts = 1;
+
+ if (of_get_property(node, "fsl,irda-mode", NULL))
+ sport->use_irda = 1;
+
+ sport->devdata = of_id->data;
+
+ return 0;
+}
+#else
+static int serial_imx_probe_dt(struct imx_port *sport,
+ struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif
+
+static int serial_imx_probe_pdata(struct imx_port *sport,
+ struct platform_device *pdev)
+{
+ struct imxuart_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return 0;
+
+ if (pdata->flags & IMXUART_HAVE_RTSCTS)
+ sport->have_rtscts = 1;
+
+ if (pdata->flags & IMXUART_IRDA)
+ sport->use_irda = 1;
+
+ sport->devdata = &imx_uart_devdata[pdev->id_entry->driver_data];
+
+ return 0;
+}
+
static int serial_imx_probe(struct platform_device *pdev)
{
struct imx_port *sport;
@@ -1262,6 +1322,12 @@ static int serial_imx_probe(struct platform_device *pdev)
if (!sport)
return -ENOMEM;
+ ret = serial_imx_probe_dt(sport, pdev);
+ if (ret == -ENODEV)
+ ret = serial_imx_probe_pdata(sport, pdev);
+ if (ret)
+ goto free;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
@@ -1290,7 +1356,6 @@ static int serial_imx_probe(struct platform_device *pdev)
init_timer(&sport->timer);
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
- sport->devdata = &imx_uart_devdata[pdev->id_entry->driver_data];
sport->clk = clk_get(&pdev->dev, "uart");
if (IS_ERR(sport->clk)) {
@@ -1301,17 +1366,13 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->port.uartclk = clk_get_rate(sport->clk);
- imx_ports[pdev->id] = sport;
+ if (imx_ports[sport->port.line]) {
+ ret = -EBUSY;
+ goto clkput;
+ }
+ imx_ports[sport->port.line] = sport;
pdata = pdev->dev.platform_data;
- if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
- sport->have_rtscts = 1;
-
-#ifdef CONFIG_IRDA
- if (pdata && (pdata->flags & IMXUART_IRDA))
- sport->use_irda = 1;
-#endif
-
if (pdata && pdata->init) {
ret = pdata->init(pdev);
if (ret)
@@ -1386,6 +1447,7 @@ static struct platform_driver serial_imx_driver = {
.driver = {
.name = "imx-uart",
.owner = THIS_MODULE,
+ .of_match_table = imx_uart_dt_ids,
},
};
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 4/5] net/fec: add device tree support
2011-06-24 18:04 [PATCH v2 0/5] Add basic device support for imx51 babbage Shawn Guo
` (2 preceding siblings ...)
2011-06-24 18:04 ` [PATCH v2 3/5] serial/imx: add device tree support Shawn Guo
@ 2011-06-24 18:04 ` Shawn Guo
2011-06-24 18:04 ` [PATCH v2 5/5] ARM: mx5: add basic device tree support for imx51 babbage Shawn Guo
4 siblings, 0 replies; 9+ messages in thread
From: Shawn Guo @ 2011-06-24 18:04 UTC (permalink / raw)
To: linux-arm-kernel
It adds device tree data parsing support for fec driver.
Signed-off-by: Jason Liu <jason.hui@linaro.org>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: David S. Miller <davem@davemloft.net>
---
Documentation/devicetree/bindings/net/fsl-fec.txt | 22 ++++++
drivers/net/fec.c | 81 +++++++++++++++++++--
2 files changed, 98 insertions(+), 5 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/fsl-fec.txt
diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
new file mode 100644
index 0000000..345ecb6
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -0,0 +1,22 @@
+* Freescale Fast Ethernet Controller (FEC)
+
+Required properties:
+- compatible : should be "fsl,<soc>-fec"
+- reg : address and length of the register set for the device
+- interrupts : should contain fec interrupt
+- phy-mode : string, operation mode of the PHY interface.
+ Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
+ "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi".
+
+Optional properties:
+- local-mac-address : 6 bytes, mac address
+
+Example:
+
+fec at 83fec000 {
+ compatible = "fsl,imx51-fec", "fsl,imx27-fec";
+ reg = <0x83fec000 0x4000>;
+ interrupts = <87>;
+ phy-mode = "mii";
+ local-mac-address = [00 04 9F 01 1B B9];
+};
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 885d8ba..16ac1dd 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -44,6 +44,8 @@
#include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/fec.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/cacheflush.h>
@@ -78,6 +80,12 @@ static struct platform_device_id fec_devtype[] = {
{ }
};
+static const struct of_device_id fec_dt_ids[] = {
+ { .compatible = "fsl,imx27-fec", .data = &fec_devtype[0], },
+ { .compatible = "fsl,imx28-fec", .data = &fec_devtype[1], },
+ {},
+};
+
static unsigned char macaddr[ETH_ALEN];
module_param_array(macaddr, byte, NULL, 0);
MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
@@ -731,8 +739,23 @@ static void __inline__ fec_get_mac(struct net_device *ndev)
*/
iap = macaddr;
+#ifdef CONFIG_OF
+ /*
+ * 2) from device tree data
+ */
+ if (!is_valid_ether_addr(iap)) {
+ struct device_node *np = fep->pdev->dev.of_node;
+ if (np) {
+ const void *p = of_get_property(np,
+ "local-mac-address", NULL);
+ if (p)
+ iap = (unsigned char *) p;
+ }
+ }
+#endif
+
/*
- * 2) from flash or fuse (via platform data)
+ * 3) from flash or fuse (via platform data)
*/
if (!is_valid_ether_addr(iap)) {
#ifdef CONFIG_M5272
@@ -745,7 +768,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev)
}
/*
- * 3) FEC mac registers set by bootloader
+ * 4) FEC mac registers set by bootloader
*/
if (!is_valid_ether_addr(iap)) {
*((unsigned long *) &tmpaddr[0]) =
@@ -1355,6 +1378,43 @@ static int fec_enet_init(struct net_device *ndev)
return 0;
}
+#ifdef CONFIG_OF
+static int __devinit fec_get_phy_mode_dt(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct device_node *np = fep->pdev->dev.of_node;
+ const char *pm, *phy_modes[] = {
+ [PHY_INTERFACE_MODE_MII] = "mii",
+ [PHY_INTERFACE_MODE_GMII] = "gmii",
+ [PHY_INTERFACE_MODE_SGMII] = "sgmii",
+ [PHY_INTERFACE_MODE_TBI] = "tbi",
+ [PHY_INTERFACE_MODE_RMII] = "rmii",
+ [PHY_INTERFACE_MODE_RGMII] = "rgmii",
+ [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
+ [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+ [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+ [PHY_INTERFACE_MODE_RTBI] = "rtbi",
+ };
+
+ if (np) {
+ pm = of_get_property(np, "phy-mode", NULL);
+ if (pm) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
+ if (!strcasecmp(pm, phy_modes[i]))
+ return i;
+ }
+ }
+
+ return -ENODEV;
+}
+#else
+static int __devinit fec_get_phy_mode_dt(struct net_device *ndev)
+{
+ return -ENODEV;
+}
+#endif
+
static int __devinit
fec_probe(struct platform_device *pdev)
{
@@ -1363,6 +1423,11 @@ fec_probe(struct platform_device *pdev)
struct net_device *ndev;
int i, irq, ret = 0;
struct resource *r;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_device(fec_dt_ids, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = (struct platform_device_id *) of_id->data;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
@@ -1394,9 +1459,14 @@ fec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
- pdata = pdev->dev.platform_data;
- if (pdata)
- fep->phy_interface = pdata->phy;
+ fep->phy_interface = fec_get_phy_mode_dt(ndev);
+ if (fep->phy_interface == -ENODEV) {
+ pdata = pdev->dev.platform_data;
+ if (pdata)
+ fep->phy_interface = pdata->phy;
+ else
+ fep->phy_interface = PHY_INTERFACE_MODE_MII;
+ }
/* This device has up to three irqs on some platforms */
for (i = 0; i < 3; i++) {
@@ -1531,6 +1601,7 @@ static struct platform_driver fec_driver = {
#ifdef CONFIG_PM
.pm = &fec_pm_ops,
#endif
+ .of_match_table = fec_dt_ids,
},
.id_table = fec_devtype,
.probe = fec_probe,
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 5/5] ARM: mx5: add basic device tree support for imx51 babbage
2011-06-24 18:04 [PATCH v2 0/5] Add basic device support for imx51 babbage Shawn Guo
` (3 preceding siblings ...)
2011-06-24 18:04 ` [PATCH v2 4/5] net/fec: " Shawn Guo
@ 2011-06-24 18:04 ` Shawn Guo
4 siblings, 0 replies; 9+ messages in thread
From: Shawn Guo @ 2011-06-24 18:04 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds the i.mx51 dt platform with uart and fec support.
It also adds the dts file imx51 babbage, so that we can have a dt
kernel on babbage booting into console with nfs root.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/boot/dts/imx51-babbage.dts | 93 +++++++++++++++++++++++++++++++++++
arch/arm/mach-mx5/Kconfig | 8 +++
arch/arm/mach-mx5/Makefile | 1 +
arch/arm/mach-mx5/imx51-dt.c | 70 ++++++++++++++++++++++++++
4 files changed, 172 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/boot/dts/imx51-babbage.dts
create mode 100644 arch/arm/mach-mx5/imx51-dt.c
diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
new file mode 100644
index 0000000..402cc44
--- /dev/null
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Freescale i.MX51 Babbage";
+ compatible = "fsl,imx51-babbage", "fsl,imx51";
+ interrupt-parent = <&tzic>;
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ };
+
+ chosen {
+ bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait";
+ };
+
+ memory {
+ reg = <0x90000000 0x20000000>;
+ };
+
+ tzic: tz-interrupt-controller at e0000000 {
+ compatible = "fsl,imx51-tzic", "fsl,tzic";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xe0000000 0x4000>;
+ };
+
+ aips at 70000000 { /* aips-1 */
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x70000000 0x10000000>;
+ ranges;
+
+ spba {
+ compatible = "fsl,spba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x70000000 0x40000>;
+ ranges;
+
+ uart2: uart at 7000c000 {
+ compatible = "fsl,imx51-uart", "fsl,imx21-uart";
+ reg = <0x7000c000 0x4000>;
+ interrupts = <33>;
+ fsl,uart-has-rtscts;
+ };
+ };
+
+ uart0: uart at 73fbc000 {
+ compatible = "fsl,imx51-uart", "fsl,imx21-uart";
+ reg = <0x73fbc000 0x4000>;
+ interrupts = <31>;
+ fsl,uart-has-rtscts;
+ };
+
+ uart1: uart at 73fc0000 {
+ compatible = "fsl,imx51-uart", "fsl,imx21-uart";
+ reg = <0x73fc0000 0x4000>;
+ interrupts = <32>;
+ fsl,uart-has-rtscts;
+ };
+ };
+
+ aips at 80000000 { /* aips-2 */
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x80000000 0x10000000>;
+ ranges;
+
+ fec at 83fec000 {
+ compatible = "fsl,imx51-fec", "fsl,imx27-fec";
+ reg = <0x83fec000 0x4000>;
+ interrupts = <87>;
+ phy-mode = "mii";
+ };
+ };
+};
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 799fbc4..8bdd0c4 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -62,6 +62,14 @@ endif # ARCH_MX50_SUPPORTED
if ARCH_MX51
comment "i.MX51 machines:"
+config MACH_IMX51_DT
+ bool "Support i.MX51 platforms from device tree"
+ select SOC_IMX51
+ select USE_OF
+ help
+ Include support for Freescale i.MX51 based platforms
+ using the device tree for discovery
+
config MACH_MX51_BABBAGE
bool "Support MX51 BABBAGE platforms"
select SOC_IMX51
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile
index 0b9338c..47b483f 100644
--- a/arch/arm/mach-mx5/Makefile
+++ b/arch/arm/mach-mx5/Makefile
@@ -7,6 +7,7 @@ obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o system.o
obj-$(CONFIG_SOC_IMX50) += mm-mx50.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o
+obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o
obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o
obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o
obj-$(CONFIG_MACH_MX53_EVK) += board-mx53_evk.o
diff --git a/arch/arm/mach-mx5/imx51-dt.c b/arch/arm/mach-mx5/imx51-dt.c
new file mode 100644
index 0000000..8bfdb91
--- /dev/null
+++ b/arch/arm/mach-mx5/imx51-dt.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/common.h>
+#include <mach/mx51.h>
+
+/*
+ * Lookup table for attaching a specific name and platform_data pointer to
+ * devices as they get created by of_platform_populate(). Ideally this table
+ * would not exist, but the current clock implementation depends on some devices
+ * having a specific name.
+ */
+static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("fsl,imx51-uart", MX51_UART1_BASE_ADDR, "imx-uart.0", NULL),
+ OF_DEV_AUXDATA("fsl,imx51-uart", MX51_UART2_BASE_ADDR, "imx-uart.1", NULL),
+ OF_DEV_AUXDATA("fsl,imx51-uart", MX51_UART3_BASE_ADDR, "imx-uart.2", NULL),
+ OF_DEV_AUXDATA("fsl,imx51-fec", MX51_FEC_BASE_ADDR, "fec.0", NULL),
+ {}
+};
+
+static const struct of_device_id tzic_of_match[] __initconst = {
+ { .compatible = "fsl,imx51-tzic", },
+ {}
+};
+
+static void __init imx51_dt_init(void)
+{
+ irq_domain_generate_simple(tzic_of_match, MX51_TZIC_BASE_ADDR, 0);
+
+ of_platform_populate(NULL, of_default_bus_match_table,
+ imx51_auxdata_lookup, NULL);
+}
+
+static void __init imx51_timer_init(void)
+{
+ mx51_clocks_init(32768, 24000000, 22579200, 0);
+}
+
+static struct sys_timer imx51_timer = {
+ .init = imx51_timer_init,
+};
+
+static const char *imx51_dt_board_compat[] __initdata = {
+ "fsl,imx51-babbage",
+ NULL
+};
+
+DT_MACHINE_START(IMX51_DT, "Freescale i.MX51 (Device Tree Support)")
+ .map_io = mx51_map_io,
+ .init_early = imx51_init_early,
+ .init_irq = mx51_init_irq,
+ .timer = &imx51_timer,
+ .init_machine = imx51_dt_init,
+ .dt_compat = imx51_dt_board_compat,
+MACHINE_END
--
1.7.4.1
^ permalink raw reply related [flat|nested] 9+ messages in thread