Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/mach-imx/cpuidle-imx6sx.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2014 Freescale Semiconductor, Inc.
4
*/
5
6
#include <linux/cpuidle.h>
7
#include <linux/cpu_pm.h>
8
#include <linux/module.h>
9
#include <asm/cacheflush.h>
10
#include <asm/cpuidle.h>
11
#include <asm/suspend.h>
12
13
#include "common.h"
14
#include "cpuidle.h"
15
#include "hardware.h"
16
17
static int imx6sx_idle_finish(unsigned long val)
18
{
19
/*
20
* for Cortex-A7 which has an internal L2
21
* cache, need to flush it before powering
22
* down ARM platform, since flushing L1 cache
23
* here again has very small overhead, compared
24
* to adding conditional code for L2 cache type,
25
* just call flush_cache_all() is fine.
26
*/
27
flush_cache_all();
28
cpu_do_idle();
29
30
return 0;
31
}
32
33
static __cpuidle int imx6sx_enter_wait(struct cpuidle_device *dev,
34
struct cpuidle_driver *drv, int index)
35
{
36
imx6_set_lpm(WAIT_UNCLOCKED);
37
38
switch (index) {
39
case 1:
40
cpu_do_idle();
41
break;
42
case 2:
43
imx6_enable_rbc(true);
44
imx_gpc_set_arm_power_in_lpm(true);
45
imx_set_cpu_jump(0, v7_cpu_resume);
46
/* Need to notify there is a cpu pm operation. */
47
cpu_pm_enter();
48
cpu_cluster_pm_enter();
49
50
ct_cpuidle_enter();
51
cpu_suspend(0, imx6sx_idle_finish);
52
ct_cpuidle_exit();
53
54
cpu_cluster_pm_exit();
55
cpu_pm_exit();
56
imx_gpc_set_arm_power_in_lpm(false);
57
imx6_enable_rbc(false);
58
break;
59
default:
60
break;
61
}
62
63
imx6_set_lpm(WAIT_CLOCKED);
64
65
return index;
66
}
67
68
static struct cpuidle_driver imx6sx_cpuidle_driver = {
69
.name = "imx6sx_cpuidle",
70
.owner = THIS_MODULE,
71
.states = {
72
/* WFI */
73
ARM_CPUIDLE_WFI_STATE,
74
/* WAIT */
75
{
76
.exit_latency = 50,
77
.target_residency = 75,
78
.flags = CPUIDLE_FLAG_TIMER_STOP,
79
.enter = imx6sx_enter_wait,
80
.name = "WAIT",
81
.desc = "Clock off",
82
},
83
/* WAIT + ARM power off */
84
{
85
/*
86
* ARM gating 31us * 5 + RBC clear 65us
87
* and some margin for SW execution, here set it
88
* to 300us.
89
*/
90
.exit_latency = 300,
91
.target_residency = 500,
92
.flags = CPUIDLE_FLAG_TIMER_STOP |
93
CPUIDLE_FLAG_RCU_IDLE,
94
.enter = imx6sx_enter_wait,
95
.name = "LOW-POWER-IDLE",
96
.desc = "ARM power off",
97
},
98
},
99
.state_count = 3,
100
.safe_state_index = 0,
101
};
102
103
int __init imx6sx_cpuidle_init(void)
104
{
105
imx6_set_int_mem_clk_lpm(true);
106
imx6_enable_rbc(false);
107
imx_gpc_set_l2_mem_power_in_lpm(false);
108
/*
109
* set ARM power up/down timing to the fastest,
110
* sw2iso and sw can be set to one 32K cycle = 31us
111
* except for power up sw2iso which need to be
112
* larger than LDO ramp up time.
113
*/
114
imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1);
115
imx_gpc_set_arm_power_down_timing(1, 1);
116
117
return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
118
}
119
120