diff mbox

[v4,3/6] drivers: cpuidle: implement OF based idle states infrastructure

Message ID 1402503520-8611-4-git-send-email-lorenzo.pieralisi@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lorenzo Pieralisi June 11, 2014, 4:18 p.m. UTC
On most common ARM systems, the low-power states a CPU can be put into are
not discoverable in HW and require device tree bindings to describe
power down suspend operations and idle states parameters.

In order to enable DT based idle states and configure idle drivers, this
patch implements the bulk infrastructure required to parse the device tree
idle states bindings and initialize the corresponding CPUidle driver states
data.

Code that initializes idle states checks the CPU idle driver cpumask so
that multiple CPU idle drivers can be initialized through it in the
kernel. The CPU idle driver cpumask defines which idle states should be
considered valid for the driver, ie idle states that are valid on a set
of cpus the idle driver manages.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
 drivers/cpuidle/Kconfig          |   9 ++
 drivers/cpuidle/Makefile         |   1 +
 drivers/cpuidle/of_idle_states.c | 282 +++++++++++++++++++++++++++++++++++++++
 drivers/cpuidle/of_idle_states.h |   8 ++
 4 files changed, 300 insertions(+)
 create mode 100644 drivers/cpuidle/of_idle_states.c
 create mode 100644 drivers/cpuidle/of_idle_states.h

Comments

Nicolas Pitre June 11, 2014, 6:24 p.m. UTC | #1
On Wed, 11 Jun 2014, Lorenzo Pieralisi wrote:

> +config OF_IDLE_STATES
> +        bool "Idle states DT support"
> +	depends on ARM || ARM64
> +	default n

The default for default is n already, so you don't have to default to 
the default's default.


Nicolas
Rafael J. Wysocki June 11, 2014, 6:25 p.m. UTC | #2
On Wed, Jun 11, 2014 at 6:18 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On most common ARM systems, the low-power states a CPU can be put into are
> not discoverable in HW and require device tree bindings to describe
> power down suspend operations and idle states parameters.
>
> In order to enable DT based idle states and configure idle drivers, this
> patch implements the bulk infrastructure required to parse the device tree
> idle states bindings and initialize the corresponding CPUidle driver states
> data.
>
> Code that initializes idle states checks the CPU idle driver cpumask so
> that multiple CPU idle drivers can be initialized through it in the
> kernel. The CPU idle driver cpumask defines which idle states should be
> considered valid for the driver, ie idle states that are valid on a set
> of cpus the idle driver manages.
>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> ---
>  drivers/cpuidle/Kconfig          |   9 ++
>  drivers/cpuidle/Makefile         |   1 +
>  drivers/cpuidle/of_idle_states.c | 282 +++++++++++++++++++++++++++++++++++++++
>  drivers/cpuidle/of_idle_states.h |   8 ++
>  4 files changed, 300 insertions(+)
>  create mode 100644 drivers/cpuidle/of_idle_states.c
>  create mode 100644 drivers/cpuidle/of_idle_states.h
>
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index 1b96fb9..760ce20 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -30,6 +30,15 @@ config CPU_IDLE_GOV_MENU
>         bool "Menu governor (for tickless system)"
>         default y
>
> +config OF_IDLE_STATES

One question here.

Do you want this to be generally useful or is it just ARM-specific?

Rafael
Nicolas Pitre June 11, 2014, 6:38 p.m. UTC | #3
On Wed, 11 Jun 2014, Lorenzo Pieralisi wrote:

> On most common ARM systems, the low-power states a CPU can be put into are
> not discoverable in HW and require device tree bindings to describe
> power down suspend operations and idle states parameters.
> 
> In order to enable DT based idle states and configure idle drivers, this
> patch implements the bulk infrastructure required to parse the device tree
> idle states bindings and initialize the corresponding CPUidle driver states
> data.

Oh and another pet peeve of mine: given we always talk about "device 
tree" all the time, could you s/OF/DT/ in the subject?  It's been a 
while that DT has outgrown its OF origins.

>  create mode 100644 drivers/cpuidle/of_idle_states.c
>  create mode 100644 drivers/cpuidle/of_idle_states.h

Ditto here, including any new symbols you introduced.

Nicolas
Lorenzo Pieralisi June 12, 2014, 8:46 a.m. UTC | #4
On Wed, Jun 11, 2014 at 07:24:12PM +0100, Nicolas Pitre wrote:
> On Wed, 11 Jun 2014, Lorenzo Pieralisi wrote:
> 
> > +config OF_IDLE_STATES
> > +        bool "Idle states DT support"
> > +	depends on ARM || ARM64
> > +	default n
> 
> The default for default is n already, so you don't have to default to 
> the default's default.

Ok, thanks for spotting that.

Lorenzo
Lorenzo Pieralisi June 12, 2014, 9:03 a.m. UTC | #5
[CC'ing Preeti and Paul to check their opinions]

Hi Rafael,

On Wed, Jun 11, 2014 at 07:25:49PM +0100, Rafael J. Wysocki wrote:
> On Wed, Jun 11, 2014 at 6:18 PM, Lorenzo Pieralisi
> <lorenzo.pieralisi@arm.com> wrote:
> > On most common ARM systems, the low-power states a CPU can be put into are
> > not discoverable in HW and require device tree bindings to describe
> > power down suspend operations and idle states parameters.
> >
> > In order to enable DT based idle states and configure idle drivers, this
> > patch implements the bulk infrastructure required to parse the device tree
> > idle states bindings and initialize the corresponding CPUidle driver states
> > data.
> >
> > Code that initializes idle states checks the CPU idle driver cpumask so
> > that multiple CPU idle drivers can be initialized through it in the
> > kernel. The CPU idle driver cpumask defines which idle states should be
> > considered valid for the driver, ie idle states that are valid on a set
> > of cpus the idle driver manages.
> >
> > Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> > ---
> >  drivers/cpuidle/Kconfig          |   9 ++
> >  drivers/cpuidle/Makefile         |   1 +
> >  drivers/cpuidle/of_idle_states.c | 282 +++++++++++++++++++++++++++++++++++++++
> >  drivers/cpuidle/of_idle_states.h |   8 ++
> >  4 files changed, 300 insertions(+)
> >  create mode 100644 drivers/cpuidle/of_idle_states.c
> >  create mode 100644 drivers/cpuidle/of_idle_states.h
> >
> > diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> > index 1b96fb9..760ce20 100644
> > --- a/drivers/cpuidle/Kconfig
> > +++ b/drivers/cpuidle/Kconfig
> > @@ -30,6 +30,15 @@ config CPU_IDLE_GOV_MENU
> >         bool "Menu governor (for tickless system)"
> >         default y
> >
> > +config OF_IDLE_STATES
> 
> One question here.
> 
> Do you want this to be generally useful or is it just ARM-specific?

The first series was targeting ARM64, then I noticed that it might be
used for ARM too (Daniel is working on that). Actually, I discovered
that Power and MIPS can reuse at least the code that initializes the
states data too, but I have to point out three things:

1) state enter function method: in my bindings it is common for all
   idle states, need to check if it applies to Power and MIPS too.
2) CPUIDLE_FLAG_TIMER_STOP and how to set it. It is non-trivial to
   add code that detects what idle states lose the tick device context.
   At the moment I am adding the flag by default to all idle states
   apart from standbywfi on ARM, but that can be optimised. Unless we
   resort to power domains (but that's not trivial), we can add a flag
   to the idle states in DT (ie local-timer-stop or suchlike) to support
   that. I think that it will be frowned upon but it is worth trying, would
   like to know what other people think about this.
3) idle states bindings should be reviewed, I expect them to be valid
   on other architectures too, but I need acknowledgments.

I think this series is not far from being ready to be upstreamed, I
would be certainly happy if it can be reused for other archs too so
just let me know.

Thanks !
Lorenzo
Lorenzo Pieralisi June 12, 2014, 9:19 a.m. UTC | #6
On Wed, Jun 11, 2014 at 07:38:51PM +0100, Nicolas Pitre wrote:
> On Wed, 11 Jun 2014, Lorenzo Pieralisi wrote:
> 
> > On most common ARM systems, the low-power states a CPU can be put into are
> > not discoverable in HW and require device tree bindings to describe
> > power down suspend operations and idle states parameters.
> > 
> > In order to enable DT based idle states and configure idle drivers, this
> > patch implements the bulk infrastructure required to parse the device tree
> > idle states bindings and initialize the corresponding CPUidle driver states
> > data.
> 
> Oh and another pet peeve of mine: given we always talk about "device 
> tree" all the time, could you s/OF/DT/ in the subject?  It's been a 
> while that DT has outgrown its OF origins.

> >  create mode 100644 drivers/cpuidle/of_idle_states.c
> >  create mode 100644 drivers/cpuidle/of_idle_states.h
> 
> Ditto here, including any new symbols you introduced.

Yes you have a point, I will do.

Thanks,
Lorenzo
preeti June 13, 2014, 3:48 a.m. UTC | #7
Hi Lorenzo,

On 06/12/2014 02:33 PM, Lorenzo Pieralisi wrote:
> [CC'ing Preeti and Paul to check their opinions]
> 
> Hi Rafael,
> 
> On Wed, Jun 11, 2014 at 07:25:49PM +0100, Rafael J. Wysocki wrote:
>> On Wed, Jun 11, 2014 at 6:18 PM, Lorenzo Pieralisi
>> <lorenzo.pieralisi@arm.com> wrote:
>>> On most common ARM systems, the low-power states a CPU can be put into are
>>> not discoverable in HW and require device tree bindings to describe
>>> power down suspend operations and idle states parameters.
>>>
>>> In order to enable DT based idle states and configure idle drivers, this
>>> patch implements the bulk infrastructure required to parse the device tree
>>> idle states bindings and initialize the corresponding CPUidle driver states
>>> data.
>>>
>>> Code that initializes idle states checks the CPU idle driver cpumask so
>>> that multiple CPU idle drivers can be initialized through it in the
>>> kernel. The CPU idle driver cpumask defines which idle states should be
>>> considered valid for the driver, ie idle states that are valid on a set
>>> of cpus the idle driver manages.
>>>
>>> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>>> ---
>>>  drivers/cpuidle/Kconfig          |   9 ++
>>>  drivers/cpuidle/Makefile         |   1 +
>>>  drivers/cpuidle/of_idle_states.c | 282 +++++++++++++++++++++++++++++++++++++++
>>>  drivers/cpuidle/of_idle_states.h |   8 ++
>>>  4 files changed, 300 insertions(+)
>>>  create mode 100644 drivers/cpuidle/of_idle_states.c
>>>  create mode 100644 drivers/cpuidle/of_idle_states.h
>>>
>>> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
>>> index 1b96fb9..760ce20 100644
>>> --- a/drivers/cpuidle/Kconfig
>>> +++ b/drivers/cpuidle/Kconfig
>>> @@ -30,6 +30,15 @@ config CPU_IDLE_GOV_MENU
>>>         bool "Menu governor (for tickless system)"
>>>         default y
>>>
>>> +config OF_IDLE_STATES
>>
>> One question here.
>>
>> Do you want this to be generally useful or is it just ARM-specific?
> 
> The first series was targeting ARM64, then I noticed that it might be
> used for ARM too (Daniel is working on that). Actually, I discovered
> that Power and MIPS can reuse at least the code that initializes the
> states data too, but I have to point out three things:
> 
> 1) state enter function method: in my bindings it is common for all
>    idle states, need to check if it applies to Power and MIPS too.

On PowerPC, we have a state enter function for each idle state. It will
not be too difficult to consolidate them into one, but that is not on
the cards right now.

> 2) CPUIDLE_FLAG_TIMER_STOP and how to set it. It is non-trivial to
>    add code that detects what idle states lose the tick device context.
>    At the moment I am adding the flag by default to all idle states
>    apart from standbywfi on ARM, but that can be optimised. Unless we
>    resort to power domains (but that's not trivial), we can add a flag
>    to the idle states in DT (ie local-timer-stop or suchlike) to support
>    that. I think that it will be frowned upon but it is worth trying, would
>    like to know what other people think about this.

On PowerPC we have a bit in flag property of the idle state device node,
which determines if timers will stop. Yes, maybe we can fix it at a
specific bit but it may be messy.

> 3) idle states bindings should be reviewed, I expect them to be valid
>    on other architectures too, but I need acknowledgments.

The major difference as I see it is the idle state bindings. In your
patch there is a device node for each idle state. On PowerPC however,
currently we have a single node with the property values of this node
determining the idle states' name, desc etc..

Besides this, the names of the device tree nodes for idle states could
be arch specific to meet some hierarchical requirements in the device
tree. This would make it difficult for this driver to parse the idle
states based on a generic idle state node name.
> 
> I think this series is not far from being ready to be upstreamed, I
> would be certainly happy if it can be reused for other archs too so
> just let me know.

On PowerPC there are a couple of other sanity checks that we ought to do
before initializing the driver.

So IMO, although we can press out the above mentioned differences in one
way or the other to make way for a generic idle driver which reads from
the device tree, I am not in favour of it since it has to concern itself
with quite a bit of arch-specific stuff. This would anyway make it less
and less of a generic idle driver. So its best to push this patch to be
ARM specific.

Regards
Preeti U Murthy
> 
> Thanks !
> Lorenzo
>
Lorenzo Pieralisi June 13, 2014, 5:16 p.m. UTC | #8
Hi Preeti,

On Fri, Jun 13, 2014 at 04:48:16AM +0100, Preeti U Murthy wrote:

[...]

> >> Do you want this to be generally useful or is it just ARM-specific?
> > 
> > The first series was targeting ARM64, then I noticed that it might be
> > used for ARM too (Daniel is working on that). Actually, I discovered
> > that Power and MIPS can reuse at least the code that initializes the
> > states data too, but I have to point out three things:
> > 
> > 1) state enter function method: in my bindings it is common for all
> >    idle states, need to check if it applies to Power and MIPS too.
> 
> On PowerPC, we have a state enter function for each idle state. It will
> not be too difficult to consolidate them into one, but that is not on
> the cards right now.

Ok, understood, it can become trickier to do when DT bindings for ARM are
merged though, but I understand it is not your priority now.

> > 2) CPUIDLE_FLAG_TIMER_STOP and how to set it. It is non-trivial to
> >    add code that detects what idle states lose the tick device context.
> >    At the moment I am adding the flag by default to all idle states
> >    apart from standbywfi on ARM, but that can be optimised. Unless we
> >    resort to power domains (but that's not trivial), we can add a flag
> >    to the idle states in DT (ie local-timer-stop or suchlike) to support
> >    that. I think that it will be frowned upon but it is worth trying, would
> >    like to know what other people think about this.
> 
> On PowerPC we have a bit in flag property of the idle state device node,
> which determines if timers will stop. Yes, maybe we can fix it at a
> specific bit but it may be messy.

It is the same information defined differently, and TIMER_STOP on Power
is inferred from the entry method. I think that with a bit of work we
could make ends meet, not sure it has to be done now though.

> > 3) idle states bindings should be reviewed, I expect them to be valid
> >    on other architectures too, but I need acknowledgments.
> 
> The major difference as I see it is the idle state bindings. In your
> patch there is a device node for each idle state. On PowerPC however,
> currently we have a single node with the property values of this node
> determining the idle states' name, desc etc..
> 
> Besides this, the names of the device tree nodes for idle states could
> be arch specific to meet some hierarchical requirements in the device
> tree. This would make it difficult for this driver to parse the idle
> states based on a generic idle state node name.
> > 
> > I think this series is not far from being ready to be upstreamed, I
> > would be certainly happy if it can be reused for other archs too so
> > just let me know.
> 
> On PowerPC there are a couple of other sanity checks that we ought to do
> before initializing the driver.
> 
> So IMO, although we can press out the above mentioned differences in one
> way or the other to make way for a generic idle driver which reads from
> the device tree, I am not in favour of it since it has to concern itself
> with quite a bit of arch-specific stuff. This would anyway make it less
> and less of a generic idle driver. So its best to push this patch to be
> ARM specific.

We are not talking about having a common idle driver for all archs, we are
talking about having a common way to initialize idle states data and I think,
as you mentioned that it could be done (from what I read in your driver).
I understand it is not a priority so I will go ahead and leave it ARM
specific for now.

Thanks,
Lorenzo
Paul Burton July 6, 2014, 10:01 a.m. UTC | #9
On Thu, Jun 12, 2014 at 10:03:39AM +0100, Lorenzo Pieralisi wrote:
> [CC'ing Preeti and Paul to check their opinions]
> 
> Hi Rafael,

snip

> > One question here.
> > 
> > Do you want this to be generally useful or is it just ARM-specific?
> 
> The first series was targeting ARM64, then I noticed that it might be
> used for ARM too (Daniel is working on that). Actually, I discovered
> that Power and MIPS can reuse at least the code that initializes the
> states data too, but I have to point out three things:
> 
> 1) state enter function method: in my bindings it is common for all
>    idle states, need to check if it applies to Power and MIPS too.
> 2) CPUIDLE_FLAG_TIMER_STOP and how to set it. It is non-trivial to
>    add code that detects what idle states lose the tick device context.
>    At the moment I am adding the flag by default to all idle states
>    apart from standbywfi on ARM, but that can be optimised. Unless we
>    resort to power domains (but that's not trivial), we can add a flag
>    to the idle states in DT (ie local-timer-stop or suchlike) to support
>    that. I think that it will be frowned upon but it is worth trying, would
>    like to know what other people think about this.
> 3) idle states bindings should be reviewed, I expect them to be valid
>    on other architectures too, but I need acknowledgments.
> 
> I think this series is not far from being ready to be upstreamed, I
> would be certainly happy if it can be reused for other archs too so
> just let me know.
> 
> Thanks !
> Lorenzo

Sorry for the delayed reply, I'm still catching up with mail after some
time off.

On the MIPS CPS systems I'm working with we are able to detect which
states are supported by reading config registers, so there's no need
for these systems to have available states described in DT.

Thanks,
    Paul
diff mbox

Patch

diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 1b96fb9..760ce20 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -30,6 +30,15 @@  config CPU_IDLE_GOV_MENU
 	bool "Menu governor (for tickless system)"
 	default y
 
+config OF_IDLE_STATES
+        bool "Idle states DT support"
+	depends on ARM || ARM64
+	default n
+	help
+	 Allows the CPU idle framework to initialize CPU idle drivers
+	 state data by using DT provided nodes compliant with idle states
+	 device tree bindings.
+
 menu "ARM CPU Idle Drivers"
 depends on ARM
 source "drivers/cpuidle/Kconfig.arm"
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index d8bb1ff..d5ebf4b 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -4,6 +4,7 @@ 
 
 obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
 obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
+obj-$(CONFIG_OF_IDLE_STATES)		  += of_idle_states.o
 
 ##################################################################################
 # ARM SoC drivers
diff --git a/drivers/cpuidle/of_idle_states.c b/drivers/cpuidle/of_idle_states.c
new file mode 100644
index 0000000..acdbf45
--- /dev/null
+++ b/drivers/cpuidle/of_idle_states.c
@@ -0,0 +1,282 @@ 
+/*
+ * OF idle states parsing code.
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "OF idle-states: " fmt
+
+#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "of_idle_states.h"
+
+struct state_elem {
+	struct list_head list;
+	struct device_node *node;
+	u32 val;
+};
+
+static struct list_head head __initdata = LIST_HEAD_INIT(head);
+
+static bool __init state_cpu_valid(struct device_node *state_node,
+				   struct device_node *cpu_node)
+{
+	int i = 0;
+	struct device_node *cpu_state;
+
+	while ((cpu_state = of_parse_phandle(cpu_node,
+					     "cpu-idle-states", i++))) {
+		if (cpu_state && state_node == cpu_state) {
+			of_node_put(cpu_state);
+			return true;
+		}
+		of_node_put(cpu_state);
+	}
+	return false;
+}
+
+static bool __init state_cpus_valid(const cpumask_t *cpus,
+				    struct device_node *state_node)
+{
+	int cpu;
+	struct device_node *cpu_node;
+
+	/*
+	 * Check if state is valid on driver cpumask cpus
+	 */
+	for_each_cpu(cpu, cpus) {
+		cpu_node = of_get_cpu_node(cpu, NULL);
+
+		if (!cpu_node) {
+			pr_err("Missing device node for CPU %d\n", cpu);
+			return false;
+		}
+
+		if (!state_cpu_valid(state_node, cpu_node))
+			return false;
+	}
+
+	return true;
+}
+
+static int __init state_cmp(void *priv, struct list_head *a,
+			    struct list_head *b)
+{
+	struct state_elem *ela, *elb;
+
+	ela = container_of(a, struct state_elem, list);
+	elb = container_of(b, struct state_elem, list);
+
+	return ela->val - elb->val;
+}
+
+static int __init add_state_node(cpumask_t *cpumask,
+				 struct device_node *state_node)
+{
+	struct state_elem *el;
+	u32 val;
+
+	pr_debug(" * %s...\n", state_node->full_name);
+
+	if (!state_cpus_valid(cpumask, state_node))
+		return -EINVAL;
+	/*
+	 * Parse just the property required to sort the states.
+	 * Since we are missing a value defining the energy
+	 * efficiency of a state, for now the sorting code uses
+	 *
+	 * exit-latency-us
+	 *
+	 * as sorting rank.
+	 */
+	if (of_property_read_u32(state_node, "exit-latency-us",
+				 &val)) {
+		pr_debug(" * %s missing exit-latency-us property\n",
+			     state_node->full_name);
+		return -EINVAL;
+	}
+
+	el = kmalloc(sizeof(*el), GFP_KERNEL);
+	if (!el) {
+		pr_err("%s failed to allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	el->node = state_node;
+	el->val = val;
+	list_add_tail(&el->list, &head);
+
+	return 0;
+}
+
+static void __init init_state_node(struct cpuidle_driver *drv,
+				   struct device_node *state_node,
+				   int *cnt)
+{
+	struct cpuidle_state *idle_state;
+
+	pr_debug(" * %s...\n", state_node->full_name);
+
+	idle_state = &drv->states[*cnt];
+
+	if (of_property_read_u32(state_node, "exit-latency-us",
+				 &idle_state->exit_latency)) {
+		pr_debug(" * %s missing exit-latency-us property\n",
+			     state_node->full_name);
+		return;
+	}
+
+	if (of_property_read_u32(state_node, "min-residency-us",
+				 &idle_state->target_residency)) {
+		pr_debug(" * %s missing min-residency-us property\n",
+			     state_node->full_name);
+		return;
+	}
+	/*
+	 * It is unknown to the idle driver if and when the tick_device
+	 * loses context when the CPU enters the idle states. To solve
+	 * this issue the tick device must be linked to a power domain
+	 * so that the idle driver can check on which states the device
+	 * loses its context. Current code takes the conservative choice
+	 * of defining the idle state as one where the tick device always
+	 * loses its context. On platforms where tick device never loses
+	 * its context (ie it is not a C3STOP device) this turns into
+	 * a nop. On platforms where the tick device does lose context in some
+	 * states, this code can be optimized, when power domain specifications
+	 * for ARM CPUs are finalized.
+	 */
+	idle_state->flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
+
+	strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN);
+	strncpy(idle_state->desc, state_node->name, CPUIDLE_NAME_LEN);
+
+	(*cnt)++;
+}
+
+static int __init init_idle_states(struct cpuidle_driver *drv,
+				   struct device_node *state_nodes[],
+				   unsigned int start_idx, bool init_nodes)
+{
+	struct state_elem *el;
+	struct list_head *curr, *tmp;
+	unsigned int cnt = start_idx;
+
+	list_for_each_entry(el, &head, list) {
+		/*
+		 * Check if the init function has to fill the
+		 * state_nodes array on behalf of the CPUidle driver.
+		 */
+		if (init_nodes)
+			state_nodes[cnt] = el->node;
+		/*
+		 * cnt is updated on return if a state was added.
+		 */
+		init_state_node(drv, el->node, &cnt);
+
+		if (cnt == CPUIDLE_STATE_MAX) {
+			pr_warn("State index reached static CPU idle state limit\n");
+			break;
+		}
+	}
+
+	drv->state_count = cnt;
+
+	list_for_each_safe(curr, tmp, &head) {
+		list_del(curr);
+		kfree(container_of(curr, struct state_elem, list));
+	}
+
+	/*
+	 * If no idle states are detected, return an error and let the idle
+	 * driver initialization fail accordingly.
+	 */
+	return (cnt > start_idx) ? 0 : -ENODATA;
+}
+
+static void __init add_idle_states(struct cpuidle_driver *drv,
+				   struct device_node *idle_states)
+{
+	struct device_node *state_node;
+
+	for_each_child_of_node(idle_states, state_node) {
+		if ((!of_device_is_compatible(state_node, "arm,idle-state"))) {
+			pr_warn(" * %s: children of /cpus/idle-states must be \"arm,idle-state\" compatible\n",
+				     state_node->full_name);
+			continue;
+		}
+		/*
+		 * If memory allocation fails, better bail out.
+		 * Initialized nodes are freed at initialization
+		 * completion in of_init_idle_driver().
+		 */
+		if ((add_state_node(drv->cpumask, state_node) == -ENOMEM))
+			break;
+	}
+	/*
+	 * Sort the states list before initializing the CPUidle driver
+	 * states array.
+	 */
+	list_sort(NULL, &head, state_cmp);
+}
+
+/**
+ * of_init_idle_driver() - Parse the DT idle states and initialize the
+ *			   idle driver states array
+ *
+ * @drv:	  Pointer to CPU idle driver to be initialized
+ * @state_nodes:  Array of struct device_nodes to be initialized if
+ *		  init_nodes == true. Must be sized CPUIDLE_STATE_MAX
+ * @start_idx:    First idle state index to be initialized
+ * @init_nodes:   Boolean to request device nodes initialization
+ *
+ * On success the states array in the cpuidle driver contains
+ * initialized entries in the states array, starting from index start_idx.
+ * If init_nodes == true, on success the state_nodes array is initialized
+ * with idle state DT node pointers, starting from index start_idx,
+ * in a 1:1 relation with the idle driver states array.
+ *
+ * Return:
+ *	0 on success
+ *	<0 on failure
+ */
+int __init of_init_idle_driver(struct cpuidle_driver *drv,
+			       struct device_node *state_nodes[],
+			       unsigned int start_idx, bool init_nodes)
+{
+	struct device_node *idle_states_node;
+	int ret;
+
+	if (start_idx >= CPUIDLE_STATE_MAX) {
+		pr_warn("State index exceeds static CPU idle driver states array size\n");
+		return -EINVAL;
+	}
+
+	if (WARN(init_nodes && !state_nodes,
+		"Requested nodes stashing in an invalid nodes container\n"))
+		return -EINVAL;
+
+	idle_states_node = of_find_node_by_path("/cpus/idle-states");
+	if (!idle_states_node)
+		return -ENOENT;
+
+	add_idle_states(drv, idle_states_node);
+
+	ret = init_idle_states(drv, state_nodes, start_idx, init_nodes);
+
+	of_node_put(idle_states_node);
+
+	return ret;
+}
diff --git a/drivers/cpuidle/of_idle_states.h b/drivers/cpuidle/of_idle_states.h
new file mode 100644
index 0000000..049f94f
--- /dev/null
+++ b/drivers/cpuidle/of_idle_states.h
@@ -0,0 +1,8 @@ 
+#ifndef __OF_IDLE_STATES
+#define __OF_IDLE_STATES
+
+int __init of_init_idle_driver(struct cpuidle_driver *drv,
+			       struct device_node *state_nodes[],
+			       unsigned int start_idx,
+			       bool init_nodes);
+#endif