-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sh: cpuidle for SuperH Mobile using hwblk
This patch adds cpuidle support for SuperH Mobile. The sleep mode selected by cpuidle is compared with the mode selected by the hwblk sleep code and the best allowed mode is entered. At this point "Sleep mode" and "Sleep mode + SF" are supported. This code can easily be extended to support "Software suspend mode", but the assembly code must first be updated to avoid loosing interrupts. Also, update the code to only copy the assembly snippet into internal memory once at bootup. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
- Loading branch information
Magnus Damm
authored and
Paul Mundt
committed
Jul 4, 2009
1 parent
a61c1a6
commit 7426394
Showing
4 changed files
with
125 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ | |
|
||
# Power Management & Sleep mode | ||
obj-$(CONFIG_PM) += pm.o sleep.o | ||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* arch/sh/kernel/cpu/shmobile/cpuidle.c | ||
* | ||
* Cpuidle support code for SuperH Mobile | ||
* | ||
* Copyright (C) 2009 Magnus Damm | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file "COPYING" in the main directory of this archive | ||
* for more details. | ||
*/ | ||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/io.h> | ||
#include <linux/suspend.h> | ||
#include <linux/cpuidle.h> | ||
#include <asm/suspend.h> | ||
#include <asm/uaccess.h> | ||
#include <asm/hwblk.h> | ||
|
||
static unsigned long cpuidle_mode[] = { | ||
SUSP_SH_SLEEP, /* regular sleep mode */ | ||
SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */ | ||
}; | ||
|
||
static int cpuidle_sleep_enter(struct cpuidle_device *dev, | ||
struct cpuidle_state *state) | ||
{ | ||
unsigned long allowed_mode = arch_hwblk_sleep_mode(); | ||
ktime_t before, after; | ||
int requested_state = state - &dev->states[0]; | ||
int allowed_state; | ||
int k; | ||
|
||
/* convert allowed mode to allowed state */ | ||
for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--) | ||
if (cpuidle_mode[k] == allowed_mode) | ||
break; | ||
|
||
allowed_state = k; | ||
|
||
/* take the following into account for sleep mode selection: | ||
* - allowed_state: best mode allowed by hardware (clock deps) | ||
* - requested_state: best mode allowed by software (latencies) | ||
*/ | ||
k = min_t(int, allowed_state, requested_state); | ||
|
||
dev->last_state = &dev->states[k]; | ||
before = ktime_get(); | ||
sh_mobile_call_standby(cpuidle_mode[k]); | ||
after = ktime_get(); | ||
return ktime_to_ns(ktime_sub(after, before)) >> 10; | ||
} | ||
|
||
static struct cpuidle_device cpuidle_dev; | ||
static struct cpuidle_driver cpuidle_driver = { | ||
.name = "sh_idle", | ||
.owner = THIS_MODULE, | ||
}; | ||
|
||
void sh_mobile_setup_cpuidle(void) | ||
{ | ||
struct cpuidle_device *dev = &cpuidle_dev; | ||
struct cpuidle_state *state; | ||
int i; | ||
|
||
cpuidle_register_driver(&cpuidle_driver); | ||
|
||
for (i = 0; i < CPUIDLE_STATE_MAX; i++) { | ||
dev->states[i].name[0] = '\0'; | ||
dev->states[i].desc[0] = '\0'; | ||
} | ||
|
||
i = CPUIDLE_DRIVER_STATE_START; | ||
|
||
state = &dev->states[i++]; | ||
snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); | ||
strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN); | ||
state->exit_latency = 1; | ||
state->target_residency = 1 * 2; | ||
state->power_usage = 3; | ||
state->flags = 0; | ||
state->flags |= CPUIDLE_FLAG_SHALLOW; | ||
state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
state->enter = cpuidle_sleep_enter; | ||
|
||
dev->safe_state = state; | ||
|
||
state = &dev->states[i++]; | ||
snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); | ||
strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN); | ||
state->exit_latency = 100; | ||
state->target_residency = 1 * 2; | ||
state->power_usage = 1; | ||
state->flags = 0; | ||
state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
state->enter = cpuidle_sleep_enter; | ||
|
||
dev->state_count = i; | ||
|
||
cpuidle_register_device(dev); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters