summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/cpuidle-imx6q.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-22 00:27:22 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-22 00:27:22 +0100
commitbab588fcfb6335c767d811a8955979f5440328e0 (patch)
tree2a862ddf47a82be885a8e7945a17cc3ff7a658b9 /arch/arm/mach-imx/cpuidle-imx6q.c
parentMerge tag 'multiplatform' of git://git.kernel.org/pub/scm/linux/kernel/git/ar... (diff)
parentARM: prima2: remove duplicate v7_invalidate_l1 (diff)
downloadlinux-bab588fcfb6335c767d811a8955979f5440328e0.tar.xz
linux-bab588fcfb6335c767d811a8955979f5440328e0.zip
Merge tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC-specific updates from Arnd Bergmann: "This is a larger set of new functionality for the existing SoC families, including: - vt8500 gains support for new CPU cores, notably the Cortex-A9 based wm8850 - prima2 gains support for the "marco" SoC family, its SMP based cousin - tegra gains support for the new Tegra4 (Tegra114) family - socfpga now supports a newer version of the hardware including SMP - i.mx31 and bcm2835 are now using DT probing for their clocks - lots of updates for sh-mobile - OMAP updates for clocks, power management and USB - i.mx6q and tegra now support cpuidle - kirkwood now supports PCIe hot plugging - tegra clock support is updated - tegra USB PHY probing gets implemented diffently" * tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (148 commits) ARM: prima2: remove duplicate v7_invalidate_l1 ARM: shmobile: r8a7779: Correct TMU clock support again ARM: prima2: fix __init section for cpu hotplug ARM: OMAP: Consolidate OMAP USB-HS platform data (part 3/3) ARM: OMAP: Consolidate OMAP USB-HS platform data (part 1/3) arm: socfpga: Add SMP support for actual socfpga harware arm: Add v7_invalidate_l1 to cache-v7.S arm: socfpga: Add entries to enable make dtbs socfpga arm: socfpga: Add new device tree source for actual socfpga HW ARM: tegra: sort Kconfig selects for Tegra114 ARM: tegra: enable ARCH_REQUIRE_GPIOLIB for Tegra114 ARM: tegra: Fix build error w/ ARCH_TEGRA_114_SOC w/o ARCH_TEGRA_3x_SOC ARM: tegra: Fix build error for gic update ARM: tegra: remove empty tegra_smp_init_cpus() ARM: shmobile: Register ARM architected timer ARM: MARCO: fix the build issue due to gic-vic-to-irqchip move ARM: shmobile: r8a7779: Correct TMU clock support ARM: mxs_defconfig: Select CONFIG_DEVTMPFS_MOUNT ARM: mxs: decrease mxs_clockevent_device.min_delta_ns to 2 clock cycles ARM: mxs: use apbx bus clock to drive the timers on timrotv2 ...
Diffstat (limited to 'arch/arm/mach-imx/cpuidle-imx6q.c')
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
new file mode 100644
index 000000000000..d533e2695f0e
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * 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/clockchips.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+#include "common.h"
+#include "cpuidle.h"
+
+static atomic_t master = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(master_lock);
+
+static int imx6q_enter_wait(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int cpu = dev->cpu;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+ /*
+ * With this lock, we prevent other cpu to exit and enter
+ * this function again and become the master.
+ */
+ if (!spin_trylock(&master_lock))
+ goto idle;
+ imx6q_set_lpm(WAIT_UNCLOCKED);
+ cpu_do_idle();
+ imx6q_set_lpm(WAIT_CLOCKED);
+ spin_unlock(&master_lock);
+ goto done;
+ }
+
+idle:
+ cpu_do_idle();
+done:
+ atomic_dec(&master);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+ return index;
+}
+
+/*
+ * For each cpu, setup the broadcast timer because local timer
+ * stops for the states other than WFI.
+ */
+static void imx6q_setup_broadcast_timer(void *arg)
+{
+ int cpu = smp_processor_id();
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
+static struct cpuidle_driver imx6q_cpuidle_driver = {
+ .name = "imx6q_cpuidle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states = {
+ /* WFI */
+ ARM_CPUIDLE_WFI_STATE,
+ /* WAIT */
+ {
+ .exit_latency = 50,
+ .target_residency = 75,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = imx6q_enter_wait,
+ .name = "WAIT",
+ .desc = "Clock off",
+ },
+ },
+ .state_count = 2,
+ .safe_state_index = 0,
+};
+
+int __init imx6q_cpuidle_init(void)
+{
+ /* Need to enable SCU standby for entering WAIT modes */
+ imx_scu_standby_enable();
+
+ /* Set chicken bit to get a reliable WAIT mode support */
+ imx6q_set_chicken_bit();
+
+ /* Configure the broadcast timer on each cpu */
+ on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
+
+ return imx_cpuidle_init(&imx6q_cpuidle_driver);
+}