Re: [PATCH 2/3] PM / OPP: Initialize OPP table from device tree

2012-07-20 Thread Menon, Nishanth
On Fri, Jul 20, 2012 at 3:46 AM, Shawn Guo  wrote:
>
>> > +   ret = of_property_read_u32_array(np, propname, opp, nr);
>> > +   if (ret) {
>> > +   dev_err(dev, "%s: Unable to read OPPs\n", __func__);
>> > +   goto out;
>> > +   }
>> > +
>> > +   nr /= 3;
>> > +   for (i = 0; i < nr; i++) {
>> > +   /*
>> > +* Each OPP is a set of tuples consisting of frequency,
>> > +* voltage and availability like .
>> > +*/
>> > +   u32 *val = opp + i * 3;
>> > +
>> > +   val[0] *= 1000;
>> > +   ret = opp_add(dev, val[0], val[1]);
>> > +   if (ret) {
>> > +   dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
>> > +__func__, val[0], ret);
>> > +   continue;
>> > +   }
>> > +
>> > +   if (!val[2]) {
>> > +   ret = opp_disable(dev, val[0]);
>> Since we are updating the table out of context of the SoC users,
>> consider what might happen if someone where to operate on the OPP
>> after opp_add, but before opp_disable?
>
> I would take this as another comment reminding me to remove the
> enabling/availability tuple from the binding.  Will do it in the
> next version.
I am not completely convinced that dropping the flag would be the best approach
on a long run, but might be a good starting point while we meet current reqs and
as a need arises, could increase the scope. Thanks once again for doing this.

Regards,
Nishanth Menon
___
devicetree-discuss mailing list
devicetree-discuss@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss


Re: [PATCH 2/3] PM / OPP: Initialize OPP table from device tree

2012-07-20 Thread Shawn Guo
Thanks for reviewing it, Nishanth.

On Fri, Jul 20, 2012 at 01:00:26AM -0500, Menon, Nishanth wrote:
> > +cpu@0 {
> > +   compatible = "arm,cortex-a9";
> I am not sure how this works - would an example of OMAP4430, 60, 70
> help? they have completely different OPP entries.
> 
Basically, patch #3 is a user of this and shows how this works.

> > +   reg = <0>;
> > +   next-level-cache = <&L2>;
> > +   operating-points = <
> > +   /* kHzuVen */
> > +   120 1275000 0
> > +   996000  1225000 1
> > +   792000  110 1
> > +   672000  110 0
> > +   396000  95  1
> > +   198000  85  1
> 
> Just my 2cents, If we change en to be a flag:
> 0 - add, but disable
> 1 - add (enabled)
> we could extend this further if the definition is a flag, for example:
> 2 - add and disable IF any of notifier chain return failure
> 3- add but dont call notifier chain (e.g. OPPs that are present for All SoC)
> 
> in addition, SoC might have additional properties associated with each
> OPP such a flag
> could be split up to mean lower 16 bits as OPP library flag and higher
> 16 bit to mean SoC custom flag
> 
> Example - On certain SoC a specific type of power technique is
> supposed to be used per OPP, such a flag
> passed on via notifiers to SoC handler might be capable of
> centralizing the OPP information into the DT.
> 
I do not follow on the idea of having the third tuple being a flag.
The binding is only meant to represent the aspects of operating-points,
while operating-points are all about frequency and voltage, nothing
else.  No Linux implementation details should be encoded here.  I'm
even a little unhappy about having enabling/availability in the third
tuple.  If anyone complains about that,  I will remove it from the
binding without a hesitation.

> > +   >;
> > +};
> > diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> > index ac993ea..2d750f9 100644
> > --- a/drivers/base/power/opp.c
> > +++ b/drivers/base/power/opp.c
> > @@ -22,6 +22,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >
> >  /*
> >   * Internal data structure organization with the OPP layer library is as
> > @@ -674,3 +675,68 @@ struct srcu_notifier_head *opp_get_notifier(struct 
> > device *dev)
> >
> > return &dev_opp->head;
> >  }
> > +
> > +#ifdef CONFIG_OF
> > +/**
> > + * of_init_opp_table() - Initialize opp table from device tree
> > + * @dev:   device pointer used to lookup device OPPs.
> > + *
> > + * Register the initial OPP table with the OPP library for given device.
> > + */
> > +int of_init_opp_table(struct device *dev)
> > +{
> > +   struct device_node *np = dev->of_node;
> > +   const char *propname = "operating-points";
> > +   const struct property *pp;
> > +   u32 *opp;
> > +   int ret, i, nr;
> > +
> > +   pp = of_find_property(np, propname, NULL);
> > +   if (!pp) {
> > +   dev_err(dev, "%s: Unable to find property", __func__);
> > +   return -ENODEV;
> > +   }
> > +
> > +   opp = kzalloc(pp->length, GFP_KERNEL);
> > +   if (!opp) {
> > +   dev_err(dev, "%s: Unable to allocate array\n", __func__);
> > +   return -ENOMEM;
> > +   }
> > +
> > +   nr = pp->length / sizeof(u32);
> error warn if the pp->length is not multiple of u32?

The DT core ensures that any integer encoded there will an u32.

> we also expect
> later on to be a multiple of 3(f,v,disable
> 
Yes, I thought about checking that, but I chose to simply ignore those
suspicious tuples at the end of the list.  I will add the check for
that, since you commented here.

> > +   ret = of_property_read_u32_array(np, propname, opp, nr);
> > +   if (ret) {
> > +   dev_err(dev, "%s: Unable to read OPPs\n", __func__);
> > +   goto out;
> > +   }
> > +
> > +   nr /= 3;
> > +   for (i = 0; i < nr; i++) {
> > +   /*
> > +* Each OPP is a set of tuples consisting of frequency,
> > +* voltage and availability like .
> > +*/
> > +   u32 *val = opp + i * 3;
> > +
> > +   val[0] *= 1000;
> > +   ret = opp_add(dev, val[0], val[1]);
> > +   if (ret) {
> > +   dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
> > +__func__, val[0], ret);
> > +   continue;
> > +   }
> > +
> > +   if (!val[2]) {
> > +   ret = opp_disable(dev, val[0]);
> Since we are updating the table out of context of the SoC users,
> consider what might happen if someone where to operate on the OPP
> after opp_add, but before opp_disable?

I would take this as another comment reminding me to remove the
enabling/availability tuple from the binding.  Will do it in the
next version.

> instead of having the 

Re: [PATCH 2/3] PM / OPP: Initialize OPP table from device tree

2012-07-19 Thread Menon, Nishanth
On Thu, Jul 19, 2012 at 10:54 AM, Shawn Guo  wrote:
> With a lot of devices booting from device tree nowadays, it requires
> that OPP table can be initialized from device tree.  The patch adds
> a helper function of_init_opp_table together with a binding doc for
> that purpose.
nice to see this happen, a quick feedback:
>
> Signed-off-by: Shawn Guo 
> ---
>  Documentation/devicetree/bindings/power/opp.txt |   29 ++
>  drivers/base/power/opp.c|   66 
> +++
>  include/linux/opp.h |4 ++
>  3 files changed, 99 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/opp.txt
>
> diff --git a/Documentation/devicetree/bindings/power/opp.txt 
> b/Documentation/devicetree/bindings/power/opp.txt
> new file mode 100644
> index 000..1dd0db2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/opp.txt
> @@ -0,0 +1,29 @@
> +* Generic OPP Interface
> +
> +SoCs have a standard set of tuples consisting of frequency and
> +voltage pairs that the device will support per voltage domain. These
> +are called Operating Performance Points or OPPs.
> +
> +Properties:
> +- operating-points: An array of 3-tuples items, and each item consists
> +  of frequency, voltage and enabling like .
> +   freq: clock frequency in kHz
> +   vol: voltage in microvolt
> +   en: initially enabled (1) or not (0)
> +
> +Examples:
> +
> +cpu@0 {
> +   compatible = "arm,cortex-a9";
I am not sure how this works - would an example of OMAP4430, 60, 70
help? they have completely different OPP entries.

> +   reg = <0>;
> +   next-level-cache = <&L2>;
> +   operating-points = <
> +   /* kHzuVen */
> +   120 1275000 0
> +   996000  1225000 1
> +   792000  110 1
> +   672000  110 0
> +   396000  95  1
> +   198000  85  1

Just my 2cents, If we change en to be a flag:
0 - add, but disable
1 - add (enabled)
we could extend this further if the definition is a flag, for example:
2 - add and disable IF any of notifier chain return failure
3- add but dont call notifier chain (e.g. OPPs that are present for All SoC)

in addition, SoC might have additional properties associated with each
OPP such a flag
could be split up to mean lower 16 bits as OPP library flag and higher
16 bit to mean SoC custom flag

Example - On certain SoC a specific type of power technique is
supposed to be used per OPP, such a flag
passed on via notifiers to SoC handler might be capable of
centralizing the OPP information into the DT.

> +   >;
> +};
> diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> index ac993ea..2d750f9 100644
> --- a/drivers/base/power/opp.c
> +++ b/drivers/base/power/opp.c
> @@ -22,6 +22,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>
>  /*
>   * Internal data structure organization with the OPP layer library is as
> @@ -674,3 +675,68 @@ struct srcu_notifier_head *opp_get_notifier(struct 
> device *dev)
>
> return &dev_opp->head;
>  }
> +
> +#ifdef CONFIG_OF
> +/**
> + * of_init_opp_table() - Initialize opp table from device tree
> + * @dev:   device pointer used to lookup device OPPs.
> + *
> + * Register the initial OPP table with the OPP library for given device.
> + */
> +int of_init_opp_table(struct device *dev)
> +{
> +   struct device_node *np = dev->of_node;
> +   const char *propname = "operating-points";
> +   const struct property *pp;
> +   u32 *opp;
> +   int ret, i, nr;
> +
> +   pp = of_find_property(np, propname, NULL);
> +   if (!pp) {
> +   dev_err(dev, "%s: Unable to find property", __func__);
> +   return -ENODEV;
> +   }
> +
> +   opp = kzalloc(pp->length, GFP_KERNEL);
> +   if (!opp) {
> +   dev_err(dev, "%s: Unable to allocate array\n", __func__);
> +   return -ENOMEM;
> +   }
> +
> +   nr = pp->length / sizeof(u32);
error warn if the pp->length is not multiple of u32? we also expect
later on to be a multiple of 3(f,v,disable

> +   ret = of_property_read_u32_array(np, propname, opp, nr);
> +   if (ret) {
> +   dev_err(dev, "%s: Unable to read OPPs\n", __func__);
> +   goto out;
> +   }
> +
> +   nr /= 3;
> +   for (i = 0; i < nr; i++) {
> +   /*
> +* Each OPP is a set of tuples consisting of frequency,
> +* voltage and availability like .
> +*/
> +   u32 *val = opp + i * 3;
> +
> +   val[0] *= 1000;
> +   ret = opp_add(dev, val[0], val[1]);
> +   if (ret) {
> +   dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
> +__func__, val[0], ret);
> +   continue;
> +   }
> +
> +   if (!val[2]) {
> + 

[PATCH 2/3] PM / OPP: Initialize OPP table from device tree

2012-07-19 Thread Shawn Guo
With a lot of devices booting from device tree nowadays, it requires
that OPP table can be initialized from device tree.  The patch adds
a helper function of_init_opp_table together with a binding doc for
that purpose.

Signed-off-by: Shawn Guo 
---
 Documentation/devicetree/bindings/power/opp.txt |   29 ++
 drivers/base/power/opp.c|   66 +++
 include/linux/opp.h |4 ++
 3 files changed, 99 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/power/opp.txt

diff --git a/Documentation/devicetree/bindings/power/opp.txt 
b/Documentation/devicetree/bindings/power/opp.txt
new file mode 100644
index 000..1dd0db2
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/opp.txt
@@ -0,0 +1,29 @@
+* Generic OPP Interface
+
+SoCs have a standard set of tuples consisting of frequency and
+voltage pairs that the device will support per voltage domain. These
+are called Operating Performance Points or OPPs.
+
+Properties:
+- operating-points: An array of 3-tuples items, and each item consists
+  of frequency, voltage and enabling like .
+   freq: clock frequency in kHz
+   vol: voltage in microvolt
+   en: initially enabled (1) or not (0)
+
+Examples:
+
+cpu@0 {
+   compatible = "arm,cortex-a9";
+   reg = <0>;
+   next-level-cache = <&L2>;
+   operating-points = <
+   /* kHzuVen */
+   120 1275000 0
+   996000  1225000 1
+   792000  110 1
+   672000  110 0
+   396000  95  1
+   198000  85  1
+   >;
+};
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index ac993ea..2d750f9 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -674,3 +675,68 @@ struct srcu_notifier_head *opp_get_notifier(struct device 
*dev)
 
return &dev_opp->head;
 }
+
+#ifdef CONFIG_OF
+/**
+ * of_init_opp_table() - Initialize opp table from device tree
+ * @dev:   device pointer used to lookup device OPPs.
+ *
+ * Register the initial OPP table with the OPP library for given device.
+ */
+int of_init_opp_table(struct device *dev)
+{
+   struct device_node *np = dev->of_node;
+   const char *propname = "operating-points";
+   const struct property *pp;
+   u32 *opp;
+   int ret, i, nr;
+
+   pp = of_find_property(np, propname, NULL);
+   if (!pp) {
+   dev_err(dev, "%s: Unable to find property", __func__);
+   return -ENODEV;
+   }
+
+   opp = kzalloc(pp->length, GFP_KERNEL);
+   if (!opp) {
+   dev_err(dev, "%s: Unable to allocate array\n", __func__);
+   return -ENOMEM;
+   }
+
+   nr = pp->length / sizeof(u32);
+   ret = of_property_read_u32_array(np, propname, opp, nr);
+   if (ret) {
+   dev_err(dev, "%s: Unable to read OPPs\n", __func__);
+   goto out;
+   }
+
+   nr /= 3;
+   for (i = 0; i < nr; i++) {
+   /*
+* Each OPP is a set of tuples consisting of frequency,
+* voltage and availability like .
+*/
+   u32 *val = opp + i * 3;
+
+   val[0] *= 1000;
+   ret = opp_add(dev, val[0], val[1]);
+   if (ret) {
+   dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
+__func__, val[0], ret);
+   continue;
+   }
+
+   if (!val[2]) {
+   ret = opp_disable(dev, val[0]);
+   if (ret)
+   dev_warn(dev, "%s: Failed to disable OPP %d: 
%d\n",
+__func__, val[0], ret);
+   }
+   }
+
+   ret = 0;
+out:
+   kfree(opp);
+   return ret;
+}
+#endif
diff --git a/include/linux/opp.h b/include/linux/opp.h
index 2a4e5fa..fd165ad 100644
--- a/include/linux/opp.h
+++ b/include/linux/opp.h
@@ -48,6 +48,10 @@ int opp_disable(struct device *dev, unsigned long freq);
 
 struct srcu_notifier_head *opp_get_notifier(struct device *dev);
 
+#ifdef CONFIG_OF
+int of_init_opp_table(struct device *dev);
+#endif
+
 #else
 static inline unsigned long opp_get_voltage(struct opp *opp)
 {
-- 
1.7.5.4


___
devicetree-discuss mailing list
devicetree-discuss@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss