[PATCH 2/2] ARM: iMX5 BBG: add cpuidle driver parameters
yong.shen at linaro.org
yong.shen at linaro.org
Tue Feb 8 10:14:44 EST 2011
From: Yong Shen <yong.shen at freescale.com>
Add cpuidle parameters to make cpuidle driver workable, but these
parameters need further tuning
Signed-off-by: Yong Shen <yong.shen at freescale.com>
---
arch/arm/mach-mx5/board-mx51_babbage.c | 114 ++++++++++++++++++++++++++++++++
arch/arm/mach-mx5/devices.c | 4 +
arch/arm/mach-mx5/devices.h | 1 +
3 files changed, 119 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c
index d9d402e..3c661e9 100644
--- a/arch/arm/mach-mx5/board-mx51_babbage.c
+++ b/arch/arm/mach-mx5/board-mx51_babbage.c
@@ -22,11 +22,13 @@
#include <linux/input.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
+#include <linux/cpuidle.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
#include <mach/mxc_ehci.h>
+#include <mach/cpuidle.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -37,6 +39,7 @@
#include "devices-imx51.h"
#include "devices.h"
#include "cpu_op-mx51.h"
+#include "crm_regs.h"
#define BABBAGE_USB_HUB_RESET IMX_GPIO_NR(1, 7)
#define BABBAGE_USBH1_STP IMX_GPIO_NR(1, 27)
@@ -333,6 +336,117 @@ static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = {
.num_chipselect = ARRAY_SIZE(mx51_babbage_spi_cs),
};
+extern int tzic_enable_wake(int is_idle);
+static int imx51_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ struct timeval before, after;
+ int idle_time;
+ u32 plat_lpc, arm_srpgcr, ccm_clpcr;
+ u32 empgc0, empgc1;
+ int stop_mode = 0;
+
+ local_irq_disable();
+ do_gettimeofday(&before);
+
+ plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) &
+ ~(MXC_CORTEXA8_PLAT_LPC_DSM);
+ ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK);
+ arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR);
+ empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR);
+ empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR);
+
+ if (state == &dev->states[0]) {
+ /* Wait clocked */
+ ;
+ } else if (state == &dev->states[1]) {
+ /* Wait unclocked */
+ ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET);
+ } else {
+ plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
+ | MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
+ arm_srpgcr |= MXC_SRPGCR_PCR;
+ if (state == &dev->states[2]) {
+ /* Wait unclocked, power off */
+ ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET);
+ ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
+ ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
+ stop_mode = 0;
+ } else if (state == &dev->states[3]) {
+ /* Stop power off */
+ ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET);
+ ccm_clpcr |= (0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET);
+ ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
+ ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
+ empgc0 |= MXC_SRPGCR_PCR;
+ empgc1 |= MXC_SRPGCR_PCR;
+ stop_mode = 1;
+ }
+ if (tzic_enable_wake(1) != 0) {
+ local_irq_enable();
+ return 0;
+ }
+ }
+
+ __raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC);
+ __raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
+ __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR);
+
+ if (stop_mode) {
+ __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR);
+ __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR);
+ }
+
+ cpu_do_idle();
+
+ do_gettimeofday(&after);
+ local_irq_enable();
+ idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+ (after.tv_usec - before.tv_usec);
+ return idle_time;
+}
+
+static struct cpuidle_state babbage_cpuidle_state[] = {
+ {
+ .enter = imx51_enter_idle,
+ .exit_latency = 1,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "WFI",
+ .desc = "Wait with clock on",
+ },
+ {
+ .enter = imx51_enter_idle,
+ .exit_latency = 100,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "WFI",
+ .desc = "Wait with clock off",
+ },
+ {
+ .enter = imx51_enter_idle,
+ .exit_latency = 10000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "WFI",
+ .desc = "Wait with clock off/power gating",
+ },
+ {
+ .enter = imx51_enter_idle,
+ .exit_latency = 1000000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "SR",
+ .desc = "state retention",
+ },
+};
+
+static struct imx_cpuidle_state babbage_cpuidle_data = {
+ .state_number = ARRAY_SIZE(babbage_cpuidle_state),
+ .state = babbage_cpuidle_state,
+};
+
+static int imx51_init_cpuidle(void)
+{
+ return mxc_register_device(&mxc_cpuidle_device, &babbage_cpuidle_data);
+}
+device_initcall(imx51_init_cpuidle);
/*
* Board specific initialization.
*/
diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c
index 153ada5..8daf5f6 100644
--- a/arch/arm/mach-mx5/devices.c
+++ b/arch/arm/mach-mx5/devices.c
@@ -37,6 +37,10 @@ struct platform_device mxc_hsi2c_device = {
.resource = mxc_hsi2c_resources
};
+struct platform_device mxc_cpuidle_device = {
+ .name = "imx_cpuidle",
+};
+
static u64 usb_dma_mask = DMA_BIT_MASK(32);
static struct resource usbotg_resources[] = {
diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h
index 55a5129..49e441c 100644
--- a/arch/arm/mach-mx5/devices.h
+++ b/arch/arm/mach-mx5/devices.h
@@ -3,3 +3,4 @@ extern struct platform_device mxc_usbh1_device;
extern struct platform_device mxc_usbh2_device;
extern struct platform_device mxc_usbdr_udc_device;
extern struct platform_device mxc_hsi2c_device;
+extern struct platform_device mxc_cpuidle_device;
--
1.7.1
More information about the linux-arm-kernel
mailing list