Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 351085
b: refs/heads/master
c: dd8af07
h: refs/heads/master
i:
  351083: 0dc1eab
v: v3
  • Loading branch information
Len Brown committed Feb 18, 2013
1 parent 794fc01 commit 7e5e87c
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 92 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 57fa8273a246d6abbbfdc995da6293b0040807d8
refs/heads/master: dd8af076262cc1ff85a8d5e0c5b1a4716d19fe25
84 changes: 59 additions & 25 deletions trunk/arch/arm/mach-davinci/cpuidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,44 +25,35 @@

#define DAVINCI_CPUIDLE_MAX_STATES 2

static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
static void __iomem *ddr2_reg_base;
static bool ddr2_pdown;

static void davinci_save_ddr_power(int enter, bool pdown)
{
u32 val;

val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);

if (enter) {
if (pdown)
val |= DDR2_SRPD_BIT;
else
val &= ~DDR2_SRPD_BIT;
val |= DDR2_LPMODEN_BIT;
} else {
val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
}

__raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
}
struct davinci_ops {
void (*enter) (u32 flags);
void (*exit) (u32 flags);
u32 flags;
};

/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
davinci_save_ddr_power(1, ddr2_pdown);
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
struct davinci_ops *ops = cpuidle_get_statedata(state_usage);

if (ops && ops->enter)
ops->enter(ops->flags);

index = cpuidle_wrap_enter(dev, drv, index,
arm_cpuidle_simple_enter);

davinci_save_ddr_power(0, ddr2_pdown);
if (ops && ops->exit)
ops->exit(ops->flags);

return index;
}

/* fields in davinci_ops.flags */
#define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN BIT(0)

static struct cpuidle_driver davinci_idle_driver = {
.name = "cpuidle-davinci",
.owner = THIS_MODULE,
Expand All @@ -79,6 +70,45 @@ static struct cpuidle_driver davinci_idle_driver = {
.state_count = DAVINCI_CPUIDLE_MAX_STATES,
};

static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
static void __iomem *ddr2_reg_base;

static void davinci_save_ddr_power(int enter, bool pdown)
{
u32 val;

val = __raw_readl(ddr2_reg_base + DDR2_SDRCR_OFFSET);

if (enter) {
if (pdown)
val |= DDR2_SRPD_BIT;
else
val &= ~DDR2_SRPD_BIT;
val |= DDR2_LPMODEN_BIT;
} else {
val &= ~(DDR2_SRPD_BIT | DDR2_LPMODEN_BIT);
}

__raw_writel(val, ddr2_reg_base + DDR2_SDRCR_OFFSET);
}

static void davinci_c2state_enter(u32 flags)
{
davinci_save_ddr_power(1, !!(flags & DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN));
}

static void davinci_c2state_exit(u32 flags)
{
davinci_save_ddr_power(0, !!(flags & DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN));
}

static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
[1] = {
.enter = davinci_c2state_enter,
.exit = davinci_c2state_exit,
},
};

static int __init davinci_cpuidle_probe(struct platform_device *pdev)
{
int ret;
Expand All @@ -94,7 +124,11 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)

ddr2_reg_base = pdata->ddr2_ctlr_base;

ddr2_pdown = pdata->ddr2_pdown;
if (pdata->ddr2_pdown)
davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);

device->state_count = DAVINCI_CPUIDLE_MAX_STATES;

ret = cpuidle_register_driver(&davinci_idle_driver);
if (ret) {
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ config APM_DO_ENABLE
this feature.

config APM_CPU_IDLE
depends on CPU_IDLE
bool "Make CPU Idle calls when idle"
---help---
Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
Expand Down
57 changes: 34 additions & 23 deletions trunk/arch/x86/kernel/apm_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@
#include <linux/acpi.h>
#include <linux/syscore_ops.h>
#include <linux/i8253.h>
#include <linux/cpuidle.h>

#include <asm/uaccess.h>
#include <asm/desc.h>
Expand Down Expand Up @@ -360,13 +361,35 @@ struct apm_user {
* idle percentage above which bios idle calls are done
*/
#ifdef CONFIG_APM_CPU_IDLE
#warning deprecated CONFIG_APM_CPU_IDLE will be deleted in 2012
#define DEFAULT_IDLE_THRESHOLD 95
#else
#define DEFAULT_IDLE_THRESHOLD 100
#endif
#define DEFAULT_IDLE_PERIOD (100 / 3)

static int apm_cpu_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);

static struct cpuidle_driver apm_idle_driver = {
.name = "apm_idle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
.states = {
{ /* entry 0 is for polling */ },
{ /* entry 1 is for APM idle */
.name = "APM",
.desc = "APM idle",
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 250, /* WAG */
.target_residency = 500, /* WAG */
.enter = &apm_cpu_idle
},
},
.state_count = 2,
};

static struct cpuidle_device apm_cpuidle_device;

/*
* Local variables
*/
Expand All @@ -377,7 +400,6 @@ static struct {
static int clock_slowed;
static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
static int set_pm_idle;
static int suspends_pending;
static int standbys_pending;
static int ignore_sys_suspend;
Expand Down Expand Up @@ -884,8 +906,6 @@ static void apm_do_busy(void)
#define IDLE_CALC_LIMIT (HZ * 100)
#define IDLE_LEAKY_MAX 16

static void (*original_pm_idle)(void) __read_mostly;

/**
* apm_cpu_idle - cpu idling for APM capable Linux
*
Expand All @@ -894,7 +914,8 @@ static void (*original_pm_idle)(void) __read_mostly;
* Furthermore it calls the system default idle routine.
*/

static void apm_cpu_idle(void)
static int apm_cpu_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
static int use_apm_idle; /* = 0 */
static unsigned int last_jiffies; /* = 0 */
Expand All @@ -904,7 +925,6 @@ static void apm_cpu_idle(void)
unsigned int jiffies_since_last_check = jiffies - last_jiffies;
unsigned int bucket;

WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012");
recalc:
if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
use_apm_idle = 0;
Expand Down Expand Up @@ -950,10 +970,7 @@ static void apm_cpu_idle(void)
break;
}
}
if (original_pm_idle)
original_pm_idle();
else
default_idle();
default_idle();
local_irq_disable();
jiffies_since_last_check = jiffies - last_jiffies;
if (jiffies_since_last_check > idle_period)
Expand All @@ -963,7 +980,7 @@ static void apm_cpu_idle(void)
if (apm_idle_done)
apm_do_busy();

local_irq_enable();
return index;
}

/**
Expand Down Expand Up @@ -2381,9 +2398,9 @@ static int __init apm_init(void)
if (HZ != 100)
idle_period = (idle_period * HZ) / 100;
if (idle_threshold < 100) {
original_pm_idle = pm_idle;
pm_idle = apm_cpu_idle;
set_pm_idle = 1;
if (!cpuidle_register_driver(&apm_idle_driver))
if (cpuidle_register_device(&apm_cpuidle_device))
cpuidle_unregister_driver(&apm_idle_driver);
}

return 0;
Expand All @@ -2393,15 +2410,9 @@ static void __exit apm_exit(void)
{
int error;

if (set_pm_idle) {
pm_idle = original_pm_idle;
/*
* We are about to unload the current idle thread pm callback
* (pm_idle), Wait for all processors to update cached/local
* copies of pm_idle before proceeding.
*/
kick_all_cpus_sync();
}
cpuidle_unregister_device(&apm_cpuidle_device);
cpuidle_unregister_driver(&apm_idle_driver);

if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
&& (apm_info.connection_version > 0x0100)) {
error = apm_engage_power_management(APM_DEVICE_ALL, 0);
Expand Down
3 changes: 0 additions & 3 deletions trunk/arch/x86/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,6 @@ EXPORT_SYMBOL(boot_option_idle_override);
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
#ifdef CONFIG_APM_MODULE
EXPORT_SYMBOL(pm_idle);
#endif

#ifndef CONFIG_SMP
static inline void play_dead(void)
Expand Down
Loading

0 comments on commit 7e5e87c

Please sign in to comment.