0001
0002
0003
0004
0005
0006 #include <linux/cpuidle.h>
0007 #include <linux/cpu_pm.h>
0008 #include <linux/module.h>
0009 #include <asm/cacheflush.h>
0010 #include <asm/cpuidle.h>
0011 #include <asm/suspend.h>
0012
0013 #include "common.h"
0014 #include "cpuidle.h"
0015 #include "hardware.h"
0016
0017 static int imx6sx_idle_finish(unsigned long val)
0018 {
0019
0020
0021
0022
0023
0024
0025
0026
0027 flush_cache_all();
0028 cpu_do_idle();
0029
0030 return 0;
0031 }
0032
0033 static int imx6sx_enter_wait(struct cpuidle_device *dev,
0034 struct cpuidle_driver *drv, int index)
0035 {
0036 imx6_set_lpm(WAIT_UNCLOCKED);
0037
0038 switch (index) {
0039 case 1:
0040 cpu_do_idle();
0041 break;
0042 case 2:
0043 imx6_enable_rbc(true);
0044 imx_gpc_set_arm_power_in_lpm(true);
0045 imx_set_cpu_jump(0, v7_cpu_resume);
0046
0047 cpu_pm_enter();
0048 cpu_cluster_pm_enter();
0049
0050 cpu_suspend(0, imx6sx_idle_finish);
0051
0052 cpu_cluster_pm_exit();
0053 cpu_pm_exit();
0054 imx_gpc_set_arm_power_in_lpm(false);
0055 imx6_enable_rbc(false);
0056 break;
0057 default:
0058 break;
0059 }
0060
0061 imx6_set_lpm(WAIT_CLOCKED);
0062
0063 return index;
0064 }
0065
0066 static struct cpuidle_driver imx6sx_cpuidle_driver = {
0067 .name = "imx6sx_cpuidle",
0068 .owner = THIS_MODULE,
0069 .states = {
0070
0071 ARM_CPUIDLE_WFI_STATE,
0072
0073 {
0074 .exit_latency = 50,
0075 .target_residency = 75,
0076 .flags = CPUIDLE_FLAG_TIMER_STOP,
0077 .enter = imx6sx_enter_wait,
0078 .name = "WAIT",
0079 .desc = "Clock off",
0080 },
0081
0082 {
0083
0084
0085
0086
0087
0088 .exit_latency = 300,
0089 .target_residency = 500,
0090 .flags = CPUIDLE_FLAG_TIMER_STOP,
0091 .enter = imx6sx_enter_wait,
0092 .name = "LOW-POWER-IDLE",
0093 .desc = "ARM power off",
0094 },
0095 },
0096 .state_count = 3,
0097 .safe_state_index = 0,
0098 };
0099
0100 int __init imx6sx_cpuidle_init(void)
0101 {
0102 imx6_set_int_mem_clk_lpm(true);
0103 imx6_enable_rbc(false);
0104 imx_gpc_set_l2_mem_power_in_lpm(false);
0105
0106
0107
0108
0109
0110
0111 imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1);
0112 imx_gpc_set_arm_power_down_timing(1, 1);
0113
0114 return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
0115 }