From fe7ea0062f2f846bb68447c7b813b9230285dbeb Mon Sep 17 00:00:00 2001 From: Mohan V Date: Fri, 22 Jun 2012 08:40:02 -0600 Subject: ARM: OMAP3: PM: correct enable/disable of daisy io chain Currently the enabling and disabling of IO Daisy chain is not according to the TRM. The below steps are followed to enable/ disable the IO chain, based loosely on the "Sec 3.5.7.2.2 I/O Wake-Up Mechanism" section in OMAP3630 Public TRM[1]. Steps to enable IO chain: [a] Set PM_WKEN_WKUP.EN_IO bit [b] Set the PM_WKEN_WKUP.EN_IO_CHAIN bit [c] Poll for PM_WKST_WKUP.ST_IO_CHAIN. [d] When ST_IO_CHAIN bit set to 1, clear PM_WKEN_WKUP.EN_IO_CHAIN [e] Clear ST_IO_CHAIN bit. Steps to disable IO chain: [a] Clear PM_WKEN_WKUP.EN_IO_CHAIN bit [b] Clear PM_WKEN_WKUP.EN_IO bit [c] Clear PM_WKST_WKUP.ST_IO bit by writing 1 to it. Step [e] & [c] in each case can be skipped, as these are handled by the PRCM interrupt handler later. [1] http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vV.zip Signed-off-by: Mohan V Signed-off-by: Vishwanath BS [paul@pwsan.com: modified commit message to clarify that these steps are based loosely on the TRM section, rather than documented exactly] Reviewed-by: Rajendra Nayak [paul@pwsan.com: resolved new warnings from checkpatch] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/pm34xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index a34023d0ca7c..6d7f0d8a3103 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -81,16 +81,17 @@ static void omap3_enable_io_chain(void) /* 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) & + while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & 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); } + omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, + PM_WKEN); + } static void omap3_disable_io_chain(void) -- cgit v1.2.3 From 09659fa72bf638ae986b8b80cf99309768dd0b32 Mon Sep 17 00:00:00 2001 From: Vishwanath BS Date: Fri, 22 Jun 2012 08:40:02 -0600 Subject: ARM: OMAP3: PM: Move IO Daisychain function to omap3 prm file Since IO Daisychain modifies only PRM registers, it makes sense to move it to PRM File. Also changed the timeout value for IO chain enable to 100us and added a wait for status disable at the end. Thanks to Nishanth Menon for contributing a fix to the timeout code waiting for WUCLKOUT to go high. Signed-off-by: Vishwanath BS Signed-off-by: Tero Kristo Cc: Nishanth Menon Reviewed-by: Rajendra Nayak [paul@pwsan.com: renamed omap3_trigger_io_chain() to better describe the end result and to match other PRM functions; removed omap3_disable_io_chain(); moved MAX_IOPAD_LATCH_TIME to prcm-common as it will also be used by the OMAP4 code; removed unnecessary barrier; added kerneldoc; added credit for fix from Nishanth] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/pm34xx.c | 35 ++--------------------------------- arch/arm/mach-omap2/prcm-common.h | 8 ++++++++ arch/arm/mach-omap2/prm2xxx_3xxx.c | 31 +++++++++++++++++++++++++++++++ arch/arm/mach-omap2/prm2xxx_3xxx.h | 2 ++ 4 files changed, 43 insertions(+), 33 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 6d7f0d8a3103..9d6cb7cc94ab 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -72,34 +72,6 @@ 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_WKST) & - OMAP3430_ST_IO_CHAIN_MASK)) { - timeout++; - if (timeout > 1000) { - pr_err("Wake up daisy chain activation failed.\n"); - return; - } - } - omap2_prm_clear_mod_reg_bits(OMAP3430_EN_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) { omap3_ctrl_save_padconf(); @@ -305,7 +277,7 @@ void omap_sram_idle(void) 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(); + omap3xxx_prm_reconfigure_io_chain(); } pwrdm_pre_transition(); @@ -382,12 +354,9 @@ void omap_sram_idle(void) /* Disable IO-PAD and IO-CHAIN wakeup */ if (omap3_has_io_wakeup() && (per_next_state < PWRDM_POWER_ON || - core_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(); - } clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); } diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 6da3ba483ad1..fca23cbea708 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -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; diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 9ce765407ad5..7d62bd654dbe 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -301,6 +301,37 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask) OMAP3_PRM_IRQENABLE_MPU_OFFSET); } +/** + * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain + * + * Clear any previously-latched I/O wakeup events and ensure that the + * I/O wakeup gates are aligned with the current mux settings. Works + * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then + * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No + * return value. + */ +void omap3xxx_prm_reconfigure_io_chain(void) +{ + int i = 0; + + omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, + PM_WKEN); + + omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & + OMAP3430_ST_IO_CHAIN_MASK, + MAX_IOPAD_LATCH_TIME, i); + if (i == MAX_IOPAD_LATCH_TIME) + pr_warn("PRM: I/O chain clock line assertion timed out\n"); + + omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, + PM_WKEN); + + omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD, + PM_WKST); + + omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); +} + static int __init omap3xxx_prcm_init(void) { if (cpu_is_omap34xx()) diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 491c72dd20a0..a8c946f318ab 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -317,6 +317,8 @@ extern u32 omap3_prm_vcvp_read(u8 offset); extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); +extern void omap3xxx_prm_reconfigure_io_chain(void); + /* PRM interrupt-related functions */ extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); extern void omap3xxx_prm_ocp_barrier(void); -- cgit v1.2.3 From fafcdd53220f44d7ae2f06a9ce20c8d550df2d9b Mon Sep 17 00:00:00 2001 From: Vishwanath BS Date: Wed, 2 May 2012 02:44:40 -0600 Subject: ARM: OMAP3: PM: Remove IO Daisychain control from cpuidle As IO Daisy chain sequence is triggered via hwmod mux, there is no need to control it from cpuidle path for OMAP3. Also as omap3_disable_io_chain is no longer being used, just remove the function. Signed-off-by: Vishwanath BS Signed-off-by: Tero Kristo Reviewed-by: Rajendra Nayak Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/pm34xx.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 9d6cb7cc94ab..9d8258f16666 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -272,13 +272,6 @@ 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()) - omap3xxx_prm_reconfigure_io_chain(); - } pwrdm_pre_transition(); @@ -351,13 +344,6 @@ void omap_sram_idle(void) 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); - clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); } -- cgit v1.2.3 From e055548953355b6e69c56f9e54388845b29b4e97 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 11 May 2012 16:00:24 -0700 Subject: ARM: OMAP2+: powerdomain: allow pre/post transtion to be per pwrdm Iteration over all power domains in the idle path is unnecessary since only power domains that are transitioning need to be accounted for. Also PRCM register accesses are known to be expensive, so the additional latency added to the idle path is signficiant. In order allow the pre/post transitions to be isolated and called per-pwrdm, change the API so passing in a specific power domain will trigger the pre/post transtion accounting for only that specific power domain. Passing NULL means iterating over all power domains as is current behavior. Reviewed-by: Santosh Shilimkar Tested-by: Santosh Shilimkar Tested-by: Grazvydas Ignotas Acked-by: Paul Walmsley Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap-mpuss-lowpower.c | 4 ++-- arch/arm/mach-omap2/pm34xx.c | 4 ++-- arch/arm/mach-omap2/powerdomain.c | 16 ++++++++++++---- arch/arm/mach-omap2/powerdomain.h | 4 ++-- 4 files changed, 18 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 13670aa84e58..e35a86bf4e1d 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -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. @@ -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; } diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index e67d898433fb..0bbbc8c82fd8 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -273,7 +273,7 @@ void omap_sram_idle(void) per_next_state = pwrdm_read_next_pwrst(per_pwrdm); core_next_state = pwrdm_read_next_pwrst(core_pwrdm); - pwrdm_pre_transition(); + pwrdm_pre_transition(NULL); /* PER */ if (per_next_state < PWRDM_POWER_ON) { @@ -338,7 +338,7 @@ void omap_sram_idle(void) } omap3_intc_resume_idle(); - pwrdm_post_transition(); + pwrdm_post_transition(NULL); /* PER */ if (per_next_state < PWRDM_POWER_ON) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 96114901b932..eefe179045e6 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -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; } diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 8f88d65c46ea..a6a4604801ad 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -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); -- cgit v1.2.3 From 58f0829b7186150318c79515f0e0850c5e7a9c89 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 11 May 2012 15:47:17 -0700 Subject: ARM: OMAP3: PM: call pre/post transition per powerdomain We only need to call the pre/post transtion methods when we know the power state is changing. First, split up the pre/post transition calls to be per-powerdomain, and then make them conditional on whether the power domain is actually changing states. Reviewed-by: Santosh Shilimkar Tested-by: Santosh Shilimkar Tested-by: Grazvydas Ignotas Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 0bbbc8c82fd8..dec2d55d7182 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -273,16 +273,21 @@ void omap_sram_idle(void) per_next_state = pwrdm_read_next_pwrst(per_pwrdm); core_next_state = pwrdm_read_next_pwrst(core_pwrdm); - pwrdm_pre_transition(NULL); + 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(); @@ -335,14 +340,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(NULL); - /* PER */ - if (per_next_state < PWRDM_POWER_ON) + if (per_next_state < PWRDM_POWER_ON) { omap2_gpio_resume_after_idle(); + pwrdm_post_transition(per_pwrdm); + } + + if (mpu_next_state < PWRDM_POWER_ON) { + pwrdm_post_transition(mpu_pwrdm); + pwrdm_post_transition(neon_pwrdm); + } clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); } -- cgit v1.2.3 From 34059a878f5cb20652cbc937f35c925f2b378831 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 19 Jun 2012 09:54:38 -0700 Subject: ARM: OMAP3: PM: cleanup cam_pwrdm leftovers commit e7410cf7 (OMAP3: PM: move device-specific special cases from PM core into CPUidle) moved mangement of cam_pwrdm to CPUidle but left some remnants behind, namely the call to clkcm_allo_idle() for the clockdomains in the MPU pwrdm. Remove these since they are not necessary and cause unwanted latency in the idle path. Acked-by: Tero Kristo Reviewed-by: Santosh Shilimkar Tested-by: Santosh Shilimkar Tested-by: Grazvydas Ignotas Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/arm/mach-omap2/pm34xx.c') diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index dec2d55d7182..e63fdd02c6f5 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -70,7 +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_core_save_context(void) { @@ -354,8 +353,6 @@ void omap_sram_idle(void) pwrdm_post_transition(mpu_pwrdm); pwrdm_post_transition(neon_pwrdm); } - - clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); } static void omap3_pm_idle(void) @@ -716,7 +713,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"); -- cgit v1.2.3