Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/kernel/cpu/shmobile/cpuidle.c
17447 views
1
/*
2
* arch/sh/kernel/cpu/shmobile/cpuidle.c
3
*
4
* Cpuidle support code for SuperH Mobile
5
*
6
* Copyright (C) 2009 Magnus Damm
7
*
8
* This file is subject to the terms and conditions of the GNU General Public
9
* License. See the file "COPYING" in the main directory of this archive
10
* for more details.
11
*/
12
#include <linux/init.h>
13
#include <linux/kernel.h>
14
#include <linux/io.h>
15
#include <linux/suspend.h>
16
#include <linux/cpuidle.h>
17
#include <asm/suspend.h>
18
#include <asm/uaccess.h>
19
#include <asm/hwblk.h>
20
21
static unsigned long cpuidle_mode[] = {
22
SUSP_SH_SLEEP, /* regular sleep mode */
23
SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */
24
SUSP_SH_STANDBY | SUSP_SH_SF, /* software standby mode + self refresh */
25
};
26
27
static int cpuidle_sleep_enter(struct cpuidle_device *dev,
28
struct cpuidle_state *state)
29
{
30
unsigned long allowed_mode = arch_hwblk_sleep_mode();
31
ktime_t before, after;
32
int requested_state = state - &dev->states[0];
33
int allowed_state;
34
int k;
35
36
/* convert allowed mode to allowed state */
37
for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)
38
if (cpuidle_mode[k] == allowed_mode)
39
break;
40
41
allowed_state = k;
42
43
/* take the following into account for sleep mode selection:
44
* - allowed_state: best mode allowed by hardware (clock deps)
45
* - requested_state: best mode allowed by software (latencies)
46
*/
47
k = min_t(int, allowed_state, requested_state);
48
49
dev->last_state = &dev->states[k];
50
before = ktime_get();
51
sh_mobile_call_standby(cpuidle_mode[k]);
52
after = ktime_get();
53
return ktime_to_ns(ktime_sub(after, before)) >> 10;
54
}
55
56
static struct cpuidle_device cpuidle_dev;
57
static struct cpuidle_driver cpuidle_driver = {
58
.name = "sh_idle",
59
.owner = THIS_MODULE,
60
};
61
62
void sh_mobile_setup_cpuidle(void)
63
{
64
struct cpuidle_device *dev = &cpuidle_dev;
65
struct cpuidle_state *state;
66
int i;
67
68
cpuidle_register_driver(&cpuidle_driver);
69
70
for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
71
dev->states[i].name[0] = '\0';
72
dev->states[i].desc[0] = '\0';
73
}
74
75
i = CPUIDLE_DRIVER_STATE_START;
76
77
state = &dev->states[i++];
78
snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
79
strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
80
state->exit_latency = 1;
81
state->target_residency = 1 * 2;
82
state->power_usage = 3;
83
state->flags = 0;
84
state->flags |= CPUIDLE_FLAG_TIME_VALID;
85
state->enter = cpuidle_sleep_enter;
86
87
dev->safe_state = state;
88
89
if (sh_mobile_sleep_supported & SUSP_SH_SF) {
90
state = &dev->states[i++];
91
snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
92
strncpy(state->desc, "SuperH Sleep Mode [SF]",
93
CPUIDLE_DESC_LEN);
94
state->exit_latency = 100;
95
state->target_residency = 1 * 2;
96
state->power_usage = 1;
97
state->flags = 0;
98
state->flags |= CPUIDLE_FLAG_TIME_VALID;
99
state->enter = cpuidle_sleep_enter;
100
}
101
102
if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
103
state = &dev->states[i++];
104
snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
105
strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
106
CPUIDLE_DESC_LEN);
107
state->exit_latency = 2300;
108
state->target_residency = 1 * 2;
109
state->power_usage = 1;
110
state->flags = 0;
111
state->flags |= CPUIDLE_FLAG_TIME_VALID;
112
state->enter = cpuidle_sleep_enter;
113
}
114
115
dev->state_count = i;
116
117
cpuidle_register_device(dev);
118
}
119
120