Use dts compatible node to init cpuidle-tc2
authormark hambleton <mahamble@broadcom.com>
Fri, 18 Jan 2013 14:16:19 +0000 (14:16 +0000)
committerJon Medhurst <tixy@linaro.org>
Mon, 1 Jul 2013 10:05:13 +0000 (11:05 +0100)
Change the init code for cpuidle-tc2 to check for a
compatible node in the devicetree of "arm,generic"
in preparation for moving it to driver/cpuidle.

Rename functions / variable from tc2_ to bl_.

Signed-off-by: mark hambleton <mahamble@broadcom.com>
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/mach-vexpress/Kconfig
arch/arm/mach-vexpress/Makefile
arch/arm/mach-vexpress/cpuidle-tc2.c [deleted file]
drivers/cpuidle/Makefile
drivers/cpuidle/arm_big_little.c [new file with mode: 0644]

index d2803be4e1a8f89ac0c9ca6c36429deb43ba65a0..1abef13f9e9756190da2d4d2db6340292710e5ef 100644 (file)
@@ -13,7 +13,7 @@
        model = "V2P-CA15_CA7";
        arm,hbi = <0x249>;
        arm,vexpress,site = <0xf>;
-       compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress";
+       compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress", "arm,generic";
        interrupt-parent = <&gic>;
        #address-cells = <2>;
        #size-cells = <2>;
index ceb7ef03d0f9cf8c98d0580672593cd1df3237e6..1ce8798e7ee2698111cd153c56e4d26ad82130ba 100644 (file)
@@ -65,15 +65,4 @@ config ARCH_VEXPRESS_TC2
        help
          Support for CPU and cluster power management on TC2.
 
-config VEXPRESS_TC2_CPUIDLE
-       bool "cpuidle support for TC2 test-chip (EXPERIMENTAL)"
-       depends on CPU_IDLE && PM && ARCH_VEXPRESS_TC2
-       select ARM_CPU_SUSPEND
-       select ARM_SPC
-       help
-         Provides code that enables CPU idle power management on the
-         TC2 testchip. It enables the CPU idle driver so that the kernel
-         can enter cluster power down states provided by the power
-         controller.
-
 endmenu
index caa3224551997340ad067eb5d276a3def84b8f8b..fd9bcfd74316d1222a518001ea82dd9d0386d3b2 100644 (file)
@@ -10,4 +10,3 @@ obj-$(CONFIG_ARCH_VEXPRESS_TC2)               += tc2_pm.o tc2_pm_setup.o
 CFLAGS_REMOVE_tc2_pm.o                 = -pg
 obj-$(CONFIG_SMP)                      += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
-obj-$(CONFIG_VEXPRESS_TC2_CPUIDLE)     += cpuidle-tc2.o
diff --git a/arch/arm/mach-vexpress/cpuidle-tc2.c b/arch/arm/mach-vexpress/cpuidle-tc2.c
deleted file mode 100644 (file)
index 1f1efc4..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * TC2 CPU idle driver.
- *
- * Copyright (C) 2012 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.
- */
-
-#include <linux/arm-cci.h>
-#include <linux/bitmap.h>
-#include <linux/cpuidle.h>
-#include <linux/cpu_pm.h>
-#include <linux/clockchips.h>
-#include <linux/debugfs.h>
-#include <linux/hrtimer.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tick.h>
-#include <linux/vexpress.h>
-#include <asm/bL_entry.h>
-#include <asm/cpuidle.h>
-#include <asm/cputype.h>
-#include <asm/idmap.h>
-#include <asm/proc-fns.h>
-#include <asm/suspend.h>
-
-#include <mach/motherboard.h>
-
-static int tc2_cpuidle_simple_enter(struct cpuidle_device *dev,
-               struct cpuidle_driver *drv, int index)
-{
-       ktime_t time_start, time_end;
-       s64 diff;
-
-       time_start = ktime_get();
-
-       cpu_do_idle();
-
-       time_end = ktime_get();
-
-       local_irq_enable();
-
-       diff = ktime_to_us(ktime_sub(time_end, time_start));
-       if (diff > INT_MAX)
-               diff = INT_MAX;
-
-       dev->last_residency = (int) diff;
-
-       return index;
-}
-
-static int tc2_enter_powerdown(struct cpuidle_device *dev,
-                               struct cpuidle_driver *drv, int idx);
-
-static struct cpuidle_state tc2_cpuidle_set[] __initdata = {
-       [0] = {
-               .enter                  = tc2_cpuidle_simple_enter,
-               .exit_latency           = 1,
-               .target_residency       = 1,
-               .power_usage            = UINT_MAX,
-               .flags                  = CPUIDLE_FLAG_TIME_VALID,
-               .name                   = "WFI",
-               .desc                   = "ARM WFI",
-       },
-       [1] = {
-               .enter                  = tc2_enter_powerdown,
-               .exit_latency           = 300,
-               .target_residency       = 1000,
-               .flags                  = CPUIDLE_FLAG_TIME_VALID,
-               .name                   = "C1",
-               .desc                   = "ARM power down",
-       },
-};
-
-struct cpuidle_driver tc2_idle_driver = {
-       .name = "tc2_idle",
-       .owner = THIS_MODULE,
-       .safe_state_index = 0
-};
-
-static DEFINE_PER_CPU(struct cpuidle_device, tc2_idle_dev);
-
-static int notrace tc2_powerdown_finisher(unsigned long arg)
-{
-       unsigned int mpidr = read_cpuid_mpidr();
-       unsigned int cluster = (mpidr >> 8) & 0xf;
-       unsigned int cpu = mpidr & 0xf;
-
-       bL_set_entry_vector(cpu, cluster, cpu_resume);
-       bL_cpu_suspend(0);  /* 0 should be replaced with better value here */
-       return 1;
-}
-
-/*
- * tc2_enter_powerdown - Programs CPU to enter the specified state
- * @dev: cpuidle device
- * @drv: The target state to be programmed
- * @idx: state index
- *
- * Called from the CPUidle framework to program the device to the
- * specified target state selected by the governor.
- */
-static int tc2_enter_powerdown(struct cpuidle_device *dev,
-                               struct cpuidle_driver *drv, int idx)
-{
-       struct timespec ts_preidle, ts_postidle, ts_idle;
-       int ret;
-
-       /* Used to keep track of the total time in idle */
-       getnstimeofday(&ts_preidle);
-
-       BUG_ON(!irqs_disabled());
-
-       cpu_pm_enter();
-
-       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
-
-       ret = cpu_suspend((unsigned long) dev, tc2_powerdown_finisher);
-       if (ret)
-               BUG();
-
-       bL_cpu_powered_up();
-
-       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
-
-       cpu_pm_exit();
-
-       getnstimeofday(&ts_postidle);
-       local_irq_enable();
-       ts_idle = timespec_sub(ts_postidle, ts_preidle);
-
-       dev->last_residency = ts_idle.tv_nsec / NSEC_PER_USEC +
-                                       ts_idle.tv_sec * USEC_PER_SEC;
-       return idx;
-}
-
-/*
- * tc2_idle_init
- *
- * Registers the TC2 specific cpuidle driver with the cpuidle
- * framework with the valid set of states.
- */
-int __init tc2_idle_init(void)
-{
-       struct cpuidle_device *dev;
-       int i, cpu_id;
-       struct cpuidle_driver *drv = &tc2_idle_driver;
-
-       if (!vexpress_spc_check_loaded()) {
-               pr_info("TC2 CPUidle not registered because no SPC found\n");
-               return -ENODEV;
-       }
-
-       drv->state_count = (sizeof(tc2_cpuidle_set) /
-                                      sizeof(struct cpuidle_state));
-
-       for (i = 0; i < drv->state_count; i++) {
-               memcpy(&drv->states[i], &tc2_cpuidle_set[i],
-                               sizeof(struct cpuidle_state));
-       }
-
-       cpuidle_register_driver(drv);
-
-       for_each_cpu(cpu_id, cpu_online_mask) {
-               pr_err("CPUidle for CPU%d registered\n", cpu_id);
-               dev = &per_cpu(tc2_idle_dev, cpu_id);
-               dev->cpu = cpu_id;
-
-               dev->state_count = drv->state_count;
-
-               if (cpuidle_register_device(dev)) {
-                       printk(KERN_ERR "%s: Cpuidle register device failed\n",
-                              __func__);
-                       return -EIO;
-               }
-       }
-
-       return 0;
-}
-
-late_initcall(tc2_idle_init);
index 0d8bd55e776f64d5e3f45c2f5d776366d98b9f86..7d8256a5ea978688beae9d354d3751336445c740 100644 (file)
@@ -4,6 +4,6 @@
 
 obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
 obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
-
+obj-$(CONFIG_BIG_LITTLE) += arm_big_little.o
 obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
 obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
diff --git a/drivers/cpuidle/arm_big_little.c b/drivers/cpuidle/arm_big_little.c
new file mode 100644 (file)
index 0000000..b97ebe0
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * big.LITTLE CPU idle driver.
+ *
+ * Copyright (C) 2012 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.
+ */
+
+#include <linux/arm-cci.h>
+#include <linux/bitmap.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
+#include <linux/clockchips.h>
+#include <linux/debugfs.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tick.h>
+#include <linux/vexpress.h>
+#include <asm/bL_entry.h>
+#include <asm/cpuidle.h>
+#include <asm/cputype.h>
+#include <asm/idmap.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <linux/of.h>
+
+static int bl_cpuidle_simple_enter(struct cpuidle_device *dev,
+               struct cpuidle_driver *drv, int index)
+{
+       ktime_t time_start, time_end;
+       s64 diff;
+
+       time_start = ktime_get();
+
+       cpu_do_idle();
+
+       time_end = ktime_get();
+
+       local_irq_enable();
+
+       diff = ktime_to_us(ktime_sub(time_end, time_start));
+       if (diff > INT_MAX)
+               diff = INT_MAX;
+
+       dev->last_residency = (int) diff;
+
+       return index;
+}
+
+static int bl_enter_powerdown(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int idx);
+
+static struct cpuidle_state bl_cpuidle_set[] __initdata = {
+       [0] = {
+               .enter                  = bl_cpuidle_simple_enter,
+               .exit_latency           = 1,
+               .target_residency       = 1,
+               .power_usage            = UINT_MAX,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID,
+               .name                   = "WFI",
+               .desc                   = "ARM WFI",
+       },
+       [1] = {
+               .enter                  = bl_enter_powerdown,
+               .exit_latency           = 300,
+               .target_residency       = 1000,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID,
+               .name                   = "C1",
+               .desc                   = "ARM power down",
+       },
+};
+
+struct cpuidle_driver bl_idle_driver = {
+       .name = "bl_idle",
+       .owner = THIS_MODULE,
+       .safe_state_index = 0
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, bl_idle_dev);
+
+static int notrace bl_powerdown_finisher(unsigned long arg)
+{
+       unsigned int mpidr = read_cpuid_mpidr();
+       unsigned int cluster = (mpidr >> 8) & 0xf;
+       unsigned int cpu = mpidr & 0xf;
+
+       bL_set_entry_vector(cpu, cluster, cpu_resume);
+       bL_cpu_suspend(0);  /* 0 should be replaced with better value here */
+       return 1;
+}
+
+/*
+ * bl_enter_powerdown - Programs CPU to enter the specified state
+ * @dev: cpuidle device
+ * @drv: The target state to be programmed
+ * @idx: state index
+ *
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ */
+static int bl_enter_powerdown(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int idx)
+{
+       struct timespec ts_preidle, ts_postidle, ts_idle;
+       int ret;
+
+       /* Used to keep track of the total time in idle */
+       getnstimeofday(&ts_preidle);
+
+       BUG_ON(!irqs_disabled());
+
+       cpu_pm_enter();
+
+       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+
+       ret = cpu_suspend((unsigned long) dev, bl_powerdown_finisher);
+       if (ret)
+               BUG();
+
+       bL_cpu_powered_up();
+
+       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+
+       cpu_pm_exit();
+
+       getnstimeofday(&ts_postidle);
+       local_irq_enable();
+       ts_idle = timespec_sub(ts_postidle, ts_preidle);
+
+       dev->last_residency = ts_idle.tv_nsec / NSEC_PER_USEC +
+                                       ts_idle.tv_sec * USEC_PER_SEC;
+       return idx;
+}
+
+/*
+ * bl_idle_init
+ *
+ * Registers the bl specific cpuidle driver with the cpuidle
+ * framework with the valid set of states.
+ */
+int __init bl_idle_init(void)
+{
+       struct cpuidle_device *dev;
+       int i, cpu_id;
+       struct cpuidle_driver *drv = &bl_idle_driver;
+
+       if (!of_find_compatible_node(NULL, NULL, "arm,generic")) {
+               pr_info("%s: No compatible node found\n", __func__);
+               return -ENODEV;
+       }
+
+       drv->state_count = (sizeof(bl_cpuidle_set) /
+                                      sizeof(struct cpuidle_state));
+
+       for (i = 0; i < drv->state_count; i++) {
+               memcpy(&drv->states[i], &bl_cpuidle_set[i],
+                               sizeof(struct cpuidle_state));
+       }
+
+       cpuidle_register_driver(drv);
+
+       for_each_cpu(cpu_id, cpu_online_mask) {
+               pr_err("CPUidle for CPU%d registered\n", cpu_id);
+               dev = &per_cpu(bl_idle_dev, cpu_id);
+               dev->cpu = cpu_id;
+
+               dev->state_count = drv->state_count;
+
+               if (cpuidle_register_device(dev)) {
+                       printk(KERN_ERR "%s: Cpuidle register device failed\n",
+                              __func__);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+late_initcall(bl_idle_init);