Skip to content

Commit

Permalink
Merge branch 'devel-pm' into tmp-merge
Browse files Browse the repository at this point in the history
  • Loading branch information
tmlind committed Jun 29, 2012
2 parents 254573d + d660e9b commit 8351bfe
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 107 deletions.
71 changes: 27 additions & 44 deletions arch/arm/mach-omap2/cpuidle34xx.c
Expand Up @@ -75,20 +75,6 @@ static struct omap3_idle_statedata omap3_idle_data[] = {

static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;

static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
struct clockdomain *clkdm)
{
clkdm_allow_idle(clkdm);
return 0;
}

static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
struct clockdomain *clkdm)
{
clkdm_deny_idle(clkdm);
return 0;
}

static int __omap3_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
Expand All @@ -106,8 +92,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,

/* Deny idle for C1 */
if (index == 0) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]);
clkdm_deny_idle(core_pd->pwrdm_clkdms[0]);
}

/*
Expand All @@ -129,8 +115,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,

/* Re-allow idle for C1 */
if (index == 0) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
clkdm_allow_idle(core_pd->pwrdm_clkdms[0]);
}

return_sleep_time:
Expand Down Expand Up @@ -176,7 +162,7 @@ static int next_valid_state(struct cpuidle_device *dev,
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
int idx;
int next_index = -1;
int next_index = 0; /* C1 is the default value */

if (enable_off_mode) {
mpu_deepest_state = PWRDM_POWER_OFF;
Expand Down Expand Up @@ -207,12 +193,6 @@ static int next_valid_state(struct cpuidle_device *dev,
}
}

/*
* C1 is always valid.
* So, no need to check for 'next_index == -1' outside
* this loop.
*/

return next_index;
}

Expand All @@ -226,23 +206,22 @@ static int next_valid_state(struct cpuidle_device *dev,
* the device to the specified or a safer state.
*/
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
struct cpuidle_driver *drv,
int index)
{
int new_state_idx;
u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
u32 core_next_state, per_next_state = 0, per_saved_state = 0;
struct omap3_idle_statedata *cx;
int ret;

/*
* Prevent idle completely if CAM is active.
* Use only C1 if CAM is active.
* CAM does not have wakeup capability in OMAP3.
*/
cam_state = pwrdm_read_pwrst(cam_pd);
if (cam_state == PWRDM_POWER_ON) {
if (pwrdm_read_pwrst(cam_pd) == PWRDM_POWER_ON)
new_state_idx = drv->safe_state_index;
goto select_state;
}
else
new_state_idx = next_valid_state(dev, drv, index);

/*
* FIXME: we currently manage device-specific idle states
Expand All @@ -252,24 +231,28 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
* its own code.
*/

/*
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
cx = &omap3_idle_data[index];
/* Program PER state */
cx = &omap3_idle_data[new_state_idx];
core_next_state = cx->core_state;
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
(core_next_state > PWRDM_POWER_RET))
per_next_state = PWRDM_POWER_RET;
if (new_state_idx == 0) {
/* In C1 do not allow PER state lower than CORE state */
if (per_next_state < core_next_state)
per_next_state = core_next_state;
} else {
/*
* Prevent PER OFF if CORE is not in RETention or OFF as this
* would disable PER wakeups completely.
*/
if ((per_next_state == PWRDM_POWER_OFF) &&
(core_next_state > PWRDM_POWER_RET))
per_next_state = PWRDM_POWER_RET;
}

/* Are we changing PER target state? */
if (per_next_state != per_saved_state)
pwrdm_set_next_pwrst(per_pd, per_next_state);

new_state_idx = next_valid_state(dev, drv, index);

select_state:
ret = omap3_enter_idle(dev, drv, new_state_idx);

/* Restore original PER state if it was modified */
Expand All @@ -286,7 +269,7 @@ struct cpuidle_driver omap3_idle_driver = {
.owner = THIS_MODULE,
.states = {
{
.enter = omap3_enter_idle,
.enter = omap3_enter_idle_bm,
.exit_latency = 2 + 2,
.target_residency = 5,
.flags = CPUIDLE_FLAG_TIME_VALID,
Expand Down
4 changes: 2 additions & 2 deletions arch/arm/mach-omap2/omap-mpuss-lowpower.c
Expand Up @@ -255,7 +255,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
return -ENXIO;
}

pwrdm_pre_transition();
pwrdm_pre_transition(NULL);

/*
* Check MPUSS next state and save interrupt controller if needed.
Expand Down Expand Up @@ -287,7 +287,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
wakeup_cpu = smp_processor_id();
set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);

pwrdm_post_transition();
pwrdm_post_transition(NULL);

return 0;
}
Expand Down
38 changes: 36 additions & 2 deletions arch/arm/mach-omap2/omap_hwmod.c
Expand Up @@ -153,6 +153,7 @@
#include "prm44xx.h"
#include "prminst44xx.h"
#include "mux.h"
#include "pm.h"

/* Maximum microseconds to wait for OMAP module to softreset */
#define MAX_MODULE_SOFTRESET_WAIT 10000
Expand Down Expand Up @@ -197,6 +198,9 @@ static LIST_HEAD(omap_hwmod_list);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;

/* io_chain_lock: used to serialize reconfigurations of the I/O chain */
static DEFINE_SPINLOCK(io_chain_lock);

/*
* linkspace: ptr to a buffer that struct omap_hwmod_link records are
* allocated from - used to reduce the number of small memory
Expand Down Expand Up @@ -1691,6 +1695,32 @@ static int _reset(struct omap_hwmod *oh)
return r;
}

/**
* _reconfigure_io_chain - clear any I/O chain wakeups and reconfigure chain
*
* Call the appropriate PRM function to clear any logged I/O chain
* wakeups and to reconfigure the chain. This apparently needs to be
* done upon every mux change. Since hwmods can be concurrently
* enabled and idled, hold a spinlock around the I/O chain
* reconfiguration sequence. No return value.
*
* XXX When the PRM code is moved to drivers, this function can be removed,
* as the PRM infrastructure should abstract this.
*/
static void _reconfigure_io_chain(void)
{
unsigned long flags;

spin_lock_irqsave(&io_chain_lock, flags);

if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl())
omap3xxx_prm_reconfigure_io_chain();
else if (cpu_is_omap44xx())
omap44xx_prm_reconfigure_io_chain();

spin_unlock_irqrestore(&io_chain_lock, flags);
}

/**
* _enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
Expand Down Expand Up @@ -1747,8 +1777,10 @@ static int _enable(struct omap_hwmod *oh)
/* Mux pins for device runtime if populated */
if (oh->mux && (!oh->mux->enabled ||
((oh->_state == _HWMOD_STATE_IDLE) &&
oh->mux->pads_dynamic)))
oh->mux->pads_dynamic))) {
omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
_reconfigure_io_chain();
}

_add_initiator_dep(oh, mpu_oh);

Expand Down Expand Up @@ -1840,8 +1872,10 @@ static int _idle(struct omap_hwmod *oh)
clkdm_hwmod_disable(oh->clkdm, oh);

/* Mux pins for device idle if populated */
if (oh->mux && oh->mux->pads_dynamic)
if (oh->mux && oh->mux->pads_dynamic) {
omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
_reconfigure_io_chain();
}

oh->_state = _HWMOD_STATE_IDLE;

Expand Down
63 changes: 13 additions & 50 deletions arch/arm/mach-omap2/pm34xx.c
Expand Up @@ -70,34 +70,6 @@ void (*omap3_do_wfi_sram)(void);

static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
static struct powerdomain *core_pwrdm, *per_pwrdm;
static struct powerdomain *cam_pwrdm;

static void omap3_enable_io_chain(void)
{
int timeout = 0;

omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
PM_WKEN);
/* Do a readback to assure write has been done */
omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);

while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
OMAP3430_ST_IO_CHAIN_MASK)) {
timeout++;
if (timeout > 1000) {
pr_err("Wake up daisy chain activation failed.\n");
return;
}
omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
WKUP_MOD, PM_WKEN);
}
}

static void omap3_disable_io_chain(void)
{
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
PM_WKEN);
}

static void omap3_core_save_context(void)
{
Expand Down Expand Up @@ -299,24 +271,22 @@ void omap_sram_idle(void)
/* Enable IO-PAD and IO-CHAIN wakeups */
per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
if (omap3_has_io_wakeup() &&
(per_next_state < PWRDM_POWER_ON ||
core_next_state < PWRDM_POWER_ON)) {
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
if (omap3_has_io_chain_ctrl())
omap3_enable_io_chain();
}

pwrdm_pre_transition();
if (mpu_next_state < PWRDM_POWER_ON) {
pwrdm_pre_transition(mpu_pwrdm);
pwrdm_pre_transition(neon_pwrdm);
}

/* PER */
if (per_next_state < PWRDM_POWER_ON) {
pwrdm_pre_transition(per_pwrdm);
per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
omap2_gpio_prepare_for_idle(per_going_off);
}

/* CORE */
if (core_next_state < PWRDM_POWER_ON) {
pwrdm_pre_transition(core_pwrdm);
if (core_next_state == PWRDM_POWER_OFF) {
omap3_core_save_context();
omap3_cm_save_context();
Expand Down Expand Up @@ -369,26 +339,20 @@ void omap_sram_idle(void)
omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
OMAP3430_GR_MOD,
OMAP3_PRM_VOLTCTRL_OFFSET);
pwrdm_post_transition(core_pwrdm);
}
omap3_intc_resume_idle();

pwrdm_post_transition();

/* PER */
if (per_next_state < PWRDM_POWER_ON)
if (per_next_state < PWRDM_POWER_ON) {
omap2_gpio_resume_after_idle();

/* Disable IO-PAD and IO-CHAIN wakeup */
if (omap3_has_io_wakeup() &&
(per_next_state < PWRDM_POWER_ON ||
core_next_state < PWRDM_POWER_ON)) {
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
PM_WKEN);
if (omap3_has_io_chain_ctrl())
omap3_disable_io_chain();
pwrdm_post_transition(per_pwrdm);
}

clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
if (mpu_next_state < PWRDM_POWER_ON) {
pwrdm_post_transition(mpu_pwrdm);
pwrdm_post_transition(neon_pwrdm);
}
}

static void omap3_pm_idle(void)
Expand Down Expand Up @@ -754,7 +718,6 @@ int __init omap3_pm_init(void)
neon_pwrdm = pwrdm_lookup("neon_pwrdm");
per_pwrdm = pwrdm_lookup("per_pwrdm");
core_pwrdm = pwrdm_lookup("core_pwrdm");
cam_pwrdm = pwrdm_lookup("cam_pwrdm");

neon_clkdm = clkdm_lookup("neon_clkdm");
mpu_clkdm = clkdm_lookup("mpu_clkdm");
Expand Down
16 changes: 12 additions & 4 deletions arch/arm/mach-omap2/powerdomain.c
Expand Up @@ -981,15 +981,23 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
return ret;
}

int pwrdm_pre_transition(void)
int pwrdm_pre_transition(struct powerdomain *pwrdm)
{
pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
if (pwrdm)
_pwrdm_pre_transition_cb(pwrdm, NULL);
else
pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);

return 0;
}

int pwrdm_post_transition(void)
int pwrdm_post_transition(struct powerdomain *pwrdm)
{
pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
if (pwrdm)
_pwrdm_post_transition_cb(pwrdm, NULL);
else
pwrdm_for_each(_pwrdm_post_transition_cb, NULL);

return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions arch/arm/mach-omap2/powerdomain.h
Expand Up @@ -213,8 +213,8 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_wait_transition(struct powerdomain *pwrdm);

int pwrdm_state_switch(struct powerdomain *pwrdm);
int pwrdm_pre_transition(void);
int pwrdm_post_transition(void);
int pwrdm_pre_transition(struct powerdomain *pwrdm);
int pwrdm_post_transition(struct powerdomain *pwrdm);
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
Expand Down
8 changes: 8 additions & 0 deletions arch/arm/mach-omap2/prcm-common.h
Expand Up @@ -410,6 +410,14 @@
*/
#define MAX_MODULE_HARDRESET_WAIT 10000

/*
* Maximum time(us) it takes to output the signal WUCLKOUT of the last
* pad of the I/O ring after asserting WUCLKIN high. Tero measured
* the actual time at 7 to 8 microseconds on OMAP3 and 2 to 4
* microseconds on OMAP4, so this timeout may be too high.
*/
#define MAX_IOPAD_LATCH_TIME 100

# ifndef __ASSEMBLER__
extern void __iomem *prm_base;
extern void __iomem *cm_base;
Expand Down

0 comments on commit 8351bfe

Please sign in to comment.