[PATCH 1/1] Added sleep support to UART
UART usage (e.g. serial console) now denies sleep for 5 seconds. This makes it possible to use serial console when dynamic idle is enabled. Also moved code from pm-debug.c to serial.c, and made pm24xx.c use this new implementation. Signed-off-by: Tero Kristo [EMAIL PROTECTED] --- arch/arm/mach-omap2/pm-debug.c | 132 arch/arm/mach-omap2/pm.h |8 -- arch/arm/mach-omap2/pm24xx.c | 53 ++- arch/arm/mach-omap2/pm34xx.c |8 ++- arch/arm/mach-omap2/serial.c | 118 include/asm-arm/arch-omap/common.h |3 + 6 files changed, 163 insertions(+), 159 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 8a9f3c4..c20fa3b 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -34,138 +34,6 @@ #ifdef CONFIG_PM_DEBUG int omap2_pm_debug = 0; -static int serial_console_clock_disabled; -static int serial_console_uart; -static unsigned int serial_console_next_disable; - -static struct clk *console_iclk, *console_fclk; - -static void serial_console_kick(void) -{ - serial_console_next_disable = omap2_read_32k_sync_counter(); - /* Keep the clocks on for 4 secs */ - serial_console_next_disable += 4 * 32768; -} - -static void serial_wait_tx(void) -{ - static const unsigned long uart_bases[3] = { - 0x4806a000, 0x4806c000, 0x4806e000 - }; - unsigned long lsr_reg; - int looped = 0; - - /* Wait for TX FIFO and THR to get empty */ - lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 2)); - while ((__raw_readb(lsr_reg) 0x60) != 0x60) - looped = 1; - if (looped) - serial_console_kick(); -} - -u32 omap2_read_32k_sync_counter(void) -{ -return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010); -} - -void serial_console_fclk_mask(u32 *f1, u32 *f2) -{ - switch (serial_console_uart) { - case 1: - *f1 = ~(1 21); - break; - case 2: - *f1 = ~(1 22); - break; - case 3: - *f2 = ~(1 2); - break; - } -} - -void serial_console_sleep(int enable) -{ - if (console_iclk == NULL || console_fclk == NULL) - return; - - if (enable) { - BUG_ON(serial_console_clock_disabled); - if (clk_get_usecount(console_fclk) == 0) - return; - if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() = 0) - return; - serial_wait_tx(); - clk_disable(console_iclk); - clk_disable(console_fclk); - serial_console_clock_disabled = 1; - } else { - int serial_wakeup = 0; - u32 l; - - switch (serial_console_uart) { - case 1: - l = prm_read_mod_reg(CORE_MOD, PM_WKST1); - if (l OMAP24XX_ST_UART1) - serial_wakeup = 1; - break; - case 2: - l = prm_read_mod_reg(CORE_MOD, PM_WKST1); - if (l OMAP24XX_ST_UART2) - serial_wakeup = 1; - break; - case 3: - l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2); - if (l OMAP24XX_ST_UART3) - serial_wakeup = 1; - break; - } - if (serial_wakeup) - serial_console_kick(); - if (!serial_console_clock_disabled) - return; - clk_enable(console_iclk); - clk_enable(console_fclk); - serial_console_clock_disabled = 0; - } -} - -void pm_init_serial_console(void) -{ - const struct omap_serial_console_config *conf; - char name[16]; - - conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE, - struct omap_serial_console_config); - if (conf == NULL) - return; - if (conf-console_uart 3 || conf-console_uart 1) - return; - serial_console_uart = conf-console_uart; - sprintf(name, uart%d_fck, conf-console_uart); - console_fclk = clk_get(NULL, name); - if (IS_ERR(console_fclk)) - console_fclk = NULL; - name[6] = 'i'; - console_iclk = clk_get(NULL, name); - if (IS_ERR(console_fclk)) - console_iclk = NULL; - if (console_fclk == NULL || console_iclk == NULL) { - serial_console_uart = 0; - return; - } - switch (serial_console_uart) { - case 1: - prm_set_mod_reg_bits(OMAP24XX_ST_UART1, CORE_MOD, PM_WKEN1); - break
Dynamic idle support for UART
This hack will most importantly allow serial console usage when dynamic idle is enabled. Note! Functionality under 24xx configuration has not been verified! There may be some problems with CONFIG_PM_DEBUG flag enabled, most likely during the PM debug information dumps after / before sleep. Without this debugging flag this patch should not affect 24xx devices. Todo: Someone to check functionality under 24xx configuration and to enable functionality by default on that platform also. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
Second part for the UART hack (dependency)
This patch depends on the PM patch set sent by Jouni Hogander. Basically just a cosmetic modification to make fclk mask look more nice inside pm34xx.c. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/1] omap3_fclks_active() now uses generic serial clock check
Signed-off-by: Tero Kristo [EMAIL PROTECTED] --- arch/arm/mach-omap2/pm34xx.c |3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index ada87ba..2574586 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -245,8 +245,7 @@ static int omap3_fclks_active(void) fck_per = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN); gpio_fclk_mask(fck_per); - fck_core1 = ~(0x3 13); - fck_per = ~(0x1 11); + omap_serial_fclk_mask(fck_core1, fck_per); if (fck_core1 | fck_core3 | fck_sgx | fck_dss | fck_cam | fck_per | fck_usbhost) return 1; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
34xx off-mode support fixes
Hi, This patch set contains some experimental fixes for the cpu-idle support from Rajendra Nayak. With this patch set, all power domains enter OFF mode and recover from it, at least while using suspend and/or dynamic idle. If you are using these patches, you should disable CPU_IDLE support from kernel config as I am not certain it works with this patch set yet. The last patch contains some trial fix to cpuidle code, so it might work also if you are lucky enough. -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] OMAP3: CPUIdle: prevent CORE from going off if doing so would reset an active clockdomain
On OMAP3 SoCs, if the CORE powerdomain enters off-mode, many other parts of the chip will be reset. If those parts of the chip are busy, the reset will disrupt them, causing unpredictable and generally undesirable results. Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Paul Walmsley p...@pwsan.com Cc: Kevin Hilman khil...@deeprootsystems.com --- arch/arm/mach-omap2/cpuidle34xx.c | 40 +++- 1 files changed, 38 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index f3e043f..d31b858 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -61,7 +61,7 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; struct powerdomain *mpu_pd, *core_pd, *per_pd; -struct powerdomain *cam_pd; +struct powerdomain *cam_pd, *dss_pd, *iva2_pd, *sgx_pd, *usb_pd; /* * The latencies/thresholds for various C states have @@ -235,7 +235,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, { struct cpuidle_state *new_state = next_valid_state(dev, state); u32 core_next_state, per_next_state = 0, per_saved_state = 0; - u32 cam_state; + u32 cam_state, dss_state, iva2_state, sgx_state, usb_state; struct omap3_processor_cx *cx; int ret; @@ -256,6 +256,8 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, *its own code. */ + /* XXX Add CORE-active check here */ + /* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. @@ -275,6 +277,36 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, (core_next_state PWRDM_POWER_RET)) per_next_state = PWRDM_POWER_RET; + /* XXX Add prevent-PER-off check here */ + + /* +* If we are attempting CORE off, check if any other powerdomains +* are at retention or higher. CORE off causes chipwide reset which +* would reset these domains also. +*/ + if (core_next_state == PWRDM_POWER_OFF) { + iva2_state = pwrdm_read_pwrst(iva2_pd); + sgx_state = pwrdm_read_pwrst(sgx_pd); + usb_state = pwrdm_read_pwrst(usb_pd); + dss_state = pwrdm_read_pwrst(dss_pd); + + if (cam_state PWRDM_POWER_OFF || + dss_state PWRDM_POWER_OFF || + iva2_state PWRDM_POWER_OFF || + per_next_state PWRDM_POWER_OFF || + sgx_state PWRDM_POWER_OFF || + usb_state PWRDM_POWER_OFF) + core_next_state = PWRDM_POWER_RET; + } + + /* Fallback to new target core/mpu state */ + while (cx-core_state core_next_state) { + state--; + cx = cpuidle_get_statedata(state); + } + + new_state = state; + /* Are we changing PER target state? */ if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); @@ -489,6 +521,10 @@ int __init omap3_idle_init(void) core_pd = pwrdm_lookup(core_pwrdm); per_pd = pwrdm_lookup(per_pwrdm); cam_pd = pwrdm_lookup(cam_pwrdm); + dss_pd = pwrdm_lookup(dss_pwrdm); + iva2_pd = pwrdm_lookup(iva2_pwrdm); + sgx_pd = pwrdm_lookup(sgx_pwrdm); + usb_pd = pwrdm_lookup(usbhost_pwrdm); omap_init_power_states(); cpuidle_register_driver(omap3_idle_driver); -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2] OMAP3: CPUIdle: prevent CORE from going off if doing so would reset an active clockdomain
On OMAP3 SoCs, if the CORE powerdomain enters off-mode, many other parts of the chip will be reset. If those parts of the chip are busy, the reset will disrupt them, causing unpredictable and generally undesirable results. This reset is caused by the core domain wakeup (COREDOMAINWKUP_RST), and it can occur for example in a case where some peripheral domain is in retention or inactive state and core enters off. This will result in the peripheral domain being reset. Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Paul Walmsley p...@pwsan.com Cc: Kevin Hilman khil...@deeprootsystems.com Cc: Santosh Shilimkar santosh.shilim...@ti.com Cc: Vishwanath Sripathy vishwanath...@ti.com --- arch/arm/mach-omap2/cpuidle34xx.c | 40 +++- 1 files changed, 38 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index f3e043f..d31b858 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -61,7 +61,7 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; struct powerdomain *mpu_pd, *core_pd, *per_pd; -struct powerdomain *cam_pd; +struct powerdomain *cam_pd, *dss_pd, *iva2_pd, *sgx_pd, *usb_pd; /* * The latencies/thresholds for various C states have @@ -235,7 +235,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, { struct cpuidle_state *new_state = next_valid_state(dev, state); u32 core_next_state, per_next_state = 0, per_saved_state = 0; - u32 cam_state; + u32 cam_state, dss_state, iva2_state, sgx_state, usb_state; struct omap3_processor_cx *cx; int ret; @@ -256,6 +256,8 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, *its own code. */ + /* XXX Add CORE-active check here */ + /* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. @@ -275,6 +277,36 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, (core_next_state PWRDM_POWER_RET)) per_next_state = PWRDM_POWER_RET; + /* XXX Add prevent-PER-off check here */ + + /* +* If we are attempting CORE off, check if any other powerdomains +* are at retention or higher. CORE off causes chipwide reset which +* would reset these domains also. +*/ + if (core_next_state == PWRDM_POWER_OFF) { + iva2_state = pwrdm_read_pwrst(iva2_pd); + sgx_state = pwrdm_read_pwrst(sgx_pd); + usb_state = pwrdm_read_pwrst(usb_pd); + dss_state = pwrdm_read_pwrst(dss_pd); + + if (cam_state PWRDM_POWER_OFF || + dss_state PWRDM_POWER_OFF || + iva2_state PWRDM_POWER_OFF || + per_next_state PWRDM_POWER_OFF || + sgx_state PWRDM_POWER_OFF || + usb_state PWRDM_POWER_OFF) + core_next_state = PWRDM_POWER_RET; + } + + /* Fallback to new target core/mpu state */ + while (cx-core_state core_next_state) { + state--; + cx = cpuidle_get_statedata(state); + } + + new_state = state; + /* Are we changing PER target state? */ if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); @@ -489,6 +521,10 @@ int __init omap3_idle_init(void) core_pd = pwrdm_lookup(core_pwrdm); per_pd = pwrdm_lookup(per_pwrdm); cam_pd = pwrdm_lookup(cam_pwrdm); + dss_pd = pwrdm_lookup(dss_pwrdm); + iva2_pd = pwrdm_lookup(iva2_pwrdm); + sgx_pd = pwrdm_lookup(sgx_pwrdm); + usb_pd = pwrdm_lookup(usbhost_pwrdm); omap_init_power_states(); cpuidle_register_driver(omap3_idle_driver); -- 1.7.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 2/6] OMAP3: PM: Added support for INACTIVE and ON states for powerdomains
From: Tero Kristo tero.kri...@nokia.com Previously omap_sram_idle() did not know about the difference between ON and INACTIVE states, which complicated the state handling in these cases. Now, the following changes are done in the idle logic: - Check for IO-chain arming is changed to reflect desired state (RET) - UART clocks will be disabled if we attempt to enter INACTIVE (this allows the state change to actually happen) Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 14 +++--- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index a5335f9..7cc3293 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -386,6 +386,7 @@ void omap_sram_idle(void) mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -452,9 +453,11 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } - /* Enable IO-PAD and IO-CHAIN wakeups */ - prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); - omap3_enable_io_chain(); + if (core_next_state = PWRDM_POWER_RET) { + /* Enable IO-PAD and IO-CHAIN wakeups */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); + } } omap3_intc_prepare_idle(); @@ -555,15 +558,13 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (core_next_state PWRDM_POWER_ON) { + if (core_next_state = PWRDM_POWER_RET) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } pwrdm_post_transition(); - - omap2_clkdm_allow_idle(mpu_pwrdm-pwrdm_clkdms[0]); } int omap3_can_sleep(void) @@ -611,7 +612,6 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) } if (sleep_switch) { - omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 5/6] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clocks and idle status bits of the domain according to following rules: 1) get inverse of idlest and mask against idle_def.mask * this gives a bitmask with non-idle bits high 2) bitwise OR active functional clocks from the domain to the result * in some cases FCLK can be active but idlest still shows module in idle 3) disable bits defined in idle_def.mask * some bits should be ignored, like UART clocks which are dynamically switched inside sleep loop These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 27 arch/arm/mach-omap2/clockdomains.h| 54 + arch/arm/mach-omap2/powerdomain.c | 25 +++ arch/arm/plat-omap/include/plat/clockdomain.h | 17 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 124 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index dd285f0..f42111a 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -472,6 +472,33 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-clk_reg_amt; i++) + if (((~cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_IDLEST + 4 * i) + clkdm-idle_def[i].mask) | + cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_FCLKEN + 4 * i)) + ~clkdm-idle_def[i].ignore) + return 0; + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index c4ee076..2c1f2eb 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -167,6 +167,12 @@ static struct clockdomain iva2_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_amt= 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -183,6 +189,12 @@ static struct clockdomain sgx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_amt= 1, + .idle_def = { + [0] = { + .mask = 0x1, + }, + }, }; /* @@ -206,6 +218,23 @@ static struct clockdomain core_l3_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_amt= 3, + .idle_def = { + [0] = { + .ignore = OMAP3430_ST_UART2_MASK | + OMAP3430_ST_UART1_MASK | + OMAP3430_ST_SDRC_MASK | + OMAP3430_ST_OMAPCTRL_MASK | + OMAP3430ES2_ST_HSOTGUSB_IDLE_MASK, + .mask = 0x, + }, + [1] = { + .mask = 0x1f, + }, + [2] = { + .mask = 0x4, + }, + }, }; static struct clockdomain core_l4_34xx_clkdm = { @@ -222,6 +251,12 @@ static struct clockdomain dss_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_amt= 1, + .idle_def = { + [0] = { + .mask = 0x1
[PATCHv3 6/6] OMAP3: CPUidle: Added peripheral pwrdm checks into bm check
From: Tero Kristo tero.kri...@nokia.com Following checks are made (and their reasoning): - If CAM domain is active, prevent idle completely * CAM pwrdm does not have HW wakeup capability - If PER is likely to remain on, prevent PER off * Saves on unnecessary context save/restore - If CORE domain is active, prevent PER off-mode * PER off in this case would prevent wakeups from PER completely - Only allow CORE off, if all peripheral domains are off * CORE off will cause a chipwide reset Also, enabled CHECK_BM flag for C2, as this is needed for the camera case. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 118 ++-- 1 files changed, 111 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4a81ef1..dad64a9 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -58,7 +58,8 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd; +struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd; +struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd; /* * The latencies/thresholds for various C states have @@ -92,6 +93,22 @@ static int omap3_idle_bm_check(void) } /** + * pwrdm_get_idle_state - Get the power state a pwrdm will enter during idle + * @pwrdm: powerdomain to check state for + * + * Checks if the powerdomain can enter idle or not, if yes, will return + * the programmed target state for the domain. Otherwise will indicate + * that the domain will stay on. + * Returns the power state the pwrdm will enter. + */ +static int pwrdm_get_idle_state(struct powerdomain *pwrdm) +{ + if (pwrdm_can_idle(pwrdm)) + return pwrdm_read_next_pwrst(pwrdm); + return PWRDM_POWER_ON; +} + +/** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device * @state: The target state to be programmed @@ -153,14 +170,94 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; - - if ((state-flags CPUIDLE_FLAG_CHECK_BM) omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); - new_state = dev-safe_state; + u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; + u32 iva2_state, sgx_state, dss_state, new_core_state; + struct omap3_processor_cx *cx; + int ret; + + if (state-flags CPUIDLE_FLAG_CHECK_BM) { + if (omap3_idle_bm_check()) { + BUG_ON(!dev-safe_state); + new_state = dev-safe_state; + goto select_state; + } + cx = cpuidle_get_statedata(state); + new_core_state = cx-core_state; + + /* Check if CORE is active, if yes, fallback to inactive */ + if (!pwrdm_can_idle(core_pd)) + new_core_state = PWRDM_POWER_INACTIVE; + + /* +* Prevent idle completely if CAM is active. +* CAM does not have wakeup capability in OMAP3. +*/ + cam_state = pwrdm_get_idle_state(cam_pd); + if (cam_state == PWRDM_POWER_ON) { + new_state = dev-safe_state; + goto select_state; + } + + /* +* Check if PER can idle or not. If we are not likely +* to idle, deny PER off. This prevents unnecessary +* context save/restore. +*/ + saved_per_state = pwrdm_read_next_pwrst(per_pd); + if (pwrdm_can_idle(per_pd)) { + per_state = saved_per_state; + /* +* Prevent PER off if CORE is active as this +* would disable PER wakeups completely +*/ + if (per_state == PWRDM_POWER_OFF + new_core_state PWRDM_POWER_RET) + per_state = PWRDM_POWER_RET; + + } else if (saved_per_state == PWRDM_POWER_OFF) + per_state = PWRDM_POWER_RET; + + /* +* If we are attempting CORE off, check if any other +* powerdomains are at retention or higher. CORE off causes +* chipwide reset which would reset these domains also. +*/ + if (new_core_state == PWRDM_POWER_OFF) { + dss_state = pwrdm_get_idle_state(dss_pd); + iva2_state = pwrdm_get_idle_state(iva2_pd); + sgx_state = pwrdm_get_idle_state(sgx_pd); + usb_state
[PATCHv3 3/6] OMAP3: CPUidle: Fixed support for ON / INACTIVE states
From: Tero Kristo tero.kri...@nokia.com New powerdomain code support for INACTIVE state removes the need to control clockdomains directly from cpuidle. Also, cpuidle state definitions can now directly support ON / INACTIVE simplifying the implementation. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 32 1 files changed, 4 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 1cfa5a6..4a81ef1 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -91,20 +91,6 @@ static int omap3_idle_bm_check(void) return 0; } -static int _cpuidle_allow_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_allow_idle(clkdm); - return 0; -} - -static int _cpuidle_deny_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_deny_idle(clkdm); - return 0; -} - /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -141,19 +127,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); - } - /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); - } - return_sleep_time: getnstimeofday(ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); @@ -246,8 +222,8 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[OMAP3_STATE_C2].threshold = cpuidle_params_table[OMAP3_STATE_C2].threshold; - omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; /* C3 . MPU CSWR + Core inactive */ @@ -261,7 +237,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; - omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; @@ -276,7 +252,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; - omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 0/6] Idle status patches revisited again
From: Tero Kristo tero.kri...@nokia.com Improvements / fixes compared to previous version: - Added pwrdm next_state cache initialization to patch 1 - Fixed changelog for patch 1 - Added FCLK checks to patch 5 (now checks both idlest and fclk) - Added more info to changelog for patch 5 -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 4/6] OMAP3: PM: Removed pwrdm state hacking from omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Following hacks will be moved inside cpuidle in subsequent patch: - CAM domain prevents idle completely - PER should not go OFF if core remains active This simplifies the design and allows cpuidle to keep better track of which power states system will actually enter. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 18 ++ 1 files changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 7cc3293..549be95 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -93,7 +93,6 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; -static struct powerdomain *cam_pwrdm; static struct prm_setup_vc prm_setup = { .clksetup = 0xff, @@ -373,7 +372,6 @@ void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -411,20 +409,11 @@ void omap_sram_idle(void) core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state PWRDM_POWER_ON) { omap2_gpio_prepare_for_idle(per_next_state); - if (per_next_state == PWRDM_POWER_OFF) { - if (core_next_state == PWRDM_POWER_ON) { - per_next_state = PWRDM_POWER_RET; - pwrdm_set_next_pwrst(per_pwrdm, per_next_state); - per_state_modified = 1; - } else - omap3_per_save_context(); - } + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); omap_uart_prepare_idle(2); } - if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) - omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* * Disable smartreflex before entering WFI. * Only needed if we are going to enter retention or off. @@ -553,8 +542,6 @@ void omap_sram_idle(void) } omap2_gpio_resume_after_idle(); omap_uart_resume_idle(2); - if (per_state_modified) - pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -1171,7 +1158,6 @@ static 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); omap_push_sram_idle(); #ifdef CONFIG_SUSPEND -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 1/6] OMAP: Powerdomains: Add support for INACTIVE state on pwrdm level
From: Tero Kristo tero.kri...@nokia.com Currently only ON, RET and OFF are supported, and ON is arguably broken as it allows the powerdomain to enter INACTIVE state unless idle is prevented. Now, pwrdm code prevents idle if ON is selected, and also adds support for INACTIVE. This simplifies the control needed inside sleep code. This patch also requires caching of next power state inside powerdomain code, as INACTIVE is not directly supported by hardware. Next powerstate is thus now stored for each powerdomain in next_state. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/powerdomain.c | 32 arch/arm/mach-omap2/powerdomains34xx.h| 26 ++-- arch/arm/plat-omap/include/plat/powerdomain.h |4 +++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 26b3f3e..a08d596 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -110,8 +110,8 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev; - int state; + u8 prev; + u8 state; if (pwrdm == NULL) return -EINVAL; @@ -218,7 +218,9 @@ int pwrdm_register(struct powerdomain *pwrdm) pr_debug(powerdomain: registered %s\n, pwrdm-name); ret = 0; - + pwrdm-next_state = + prm_read_mod_bits_shift(pwrdm-prcm_offs, PM_PWSTCTRL, + OMAP_POWERSTATE_MASK); pr_unlock: write_unlock_irqrestore(pwrdm_rwlock, flags); @@ -699,19 +701,38 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) */ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) { + u8 prg_pwrst; + if (!pwrdm) return -EINVAL; + if (pwrdm-next_state == pwrst) + return 0; + if (!(pwrdm-pwrsts (1 pwrst))) return -EINVAL; pr_debug(powerdomain: setting next powerstate for %s to %0x\n, pwrdm-name, pwrst); + /* INACTIVE is reserved, so we program pwrdm as ON */ + if (pwrst == PWRDM_POWER_INACTIVE) + prg_pwrst = PWRDM_POWER_ON; + else + prg_pwrst = pwrst; + prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, -(pwrst OMAP_POWERSTATE_SHIFT), +(prg_pwrst OMAP_POWERSTATE_SHIFT), pwrdm-prcm_offs, PM_PWSTCTRL); + /* If next state is ON, prevent idle */ + if (pwrst == PWRDM_POWER_ON) + omap2_clkdm_deny_idle(pwrdm-pwrdm_clkdms[0]); + else + omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); + + pwrdm-next_state = pwrst; + return 0; } @@ -728,8 +749,7 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm-prcm_offs, PM_PWSTCTRL, - OMAP_POWERSTATE_MASK); + return pwrdm-next_state; } /** diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index 588f7e0..f50a3f2 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -165,7 +165,7 @@ static struct powerdomain iva2_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, .wkdep_srcs = iva2_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks= 4, .pwrsts_mem_ret = { @@ -188,7 +188,7 @@ static struct powerdomain mpu_34xx_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_EN_MPU_SHIFT, .wkdep_srcs = mpu_34xx_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .flags= PWRDM_HAS_MPU_QUIRK, .banks= 1, @@ -207,7 +207,7 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0), - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .dep_bit = OMAP3430_EN_CORE_SHIFT, .banks= 2, .pwrsts_mem_ret = { @@ -215,8 +215,8 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { [1] = PWRSTS_OFF_RET,/* MEM2RETSTATE */ }, .pwrsts_mem_on= { - [0
[PATCHv4 5/8] OMAP3: PM: Removed pwrdm state hacking from omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Following hacks will be moved inside cpuidle in subsequent patch: - CAM domain prevents idle completely - PER should not go OFF if core remains active This simplifies the design and allows cpuidle to keep better track of which power states system will actually enter. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 18 ++ 1 files changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index dceb18f..f7bb5c7 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -93,7 +93,6 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; -static struct powerdomain *cam_pwrdm; static struct prm_setup_vc prm_setup = { .clksetup = 0xff, @@ -373,7 +372,6 @@ void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -411,20 +409,11 @@ void omap_sram_idle(void) core_next_state = pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state PWRDM_POWER_ON) { omap2_gpio_prepare_for_idle(per_next_state); - if (per_next_state == PWRDM_POWER_OFF) { - if (core_next_state == PWRDM_POWER_ON) { - per_next_state = PWRDM_POWER_RET; - pwrdm_set_next_pwrst(per_pwrdm, per_next_state); - per_state_modified = 1; - } else - omap3_per_save_context(); - } + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); omap_uart_prepare_idle(2); } - if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) - omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* * Disable smartreflex before entering WFI. * Only needed if we are going to enter retention or off. @@ -554,8 +543,6 @@ void omap_sram_idle(void) } omap2_gpio_resume_after_idle(); omap_uart_resume_idle(2); - if (per_state_modified) - pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -1175,7 +1162,6 @@ static 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); omap_push_sram_idle(); #ifdef CONFIG_SUSPEND -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 8/8] OMAP3: CPUidle: Added peripheral pwrdm checks into bm check
From: Tero Kristo tero.kri...@nokia.com Following checks are made (and their reasoning): - If CAM domain is active, prevent idle completely * CAM pwrdm does not have HW wakeup capability - If PER is likely to remain on, prevent PER off * Saves on unnecessary context save/restore - If CORE domain is active, prevent PER off-mode * PER off in this case would prevent wakeups from PER completely - Only allow CORE off, if all peripheral domains are off * CORE off will cause a chipwide reset Also, enabled CHECK_BM flag for C2, as this is needed for the camera case. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 118 ++-- 1 files changed, 111 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4a81ef1..dad64a9 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -58,7 +58,8 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd; +struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd; +struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd; /* * The latencies/thresholds for various C states have @@ -92,6 +93,22 @@ static int omap3_idle_bm_check(void) } /** + * pwrdm_get_idle_state - Get the power state a pwrdm will enter during idle + * @pwrdm: powerdomain to check state for + * + * Checks if the powerdomain can enter idle or not, if yes, will return + * the programmed target state for the domain. Otherwise will indicate + * that the domain will stay on. + * Returns the power state the pwrdm will enter. + */ +static int pwrdm_get_idle_state(struct powerdomain *pwrdm) +{ + if (pwrdm_can_idle(pwrdm)) + return pwrdm_read_next_pwrst(pwrdm); + return PWRDM_POWER_ON; +} + +/** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device * @state: The target state to be programmed @@ -153,14 +170,94 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; - - if ((state-flags CPUIDLE_FLAG_CHECK_BM) omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); - new_state = dev-safe_state; + u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; + u32 iva2_state, sgx_state, dss_state, new_core_state; + struct omap3_processor_cx *cx; + int ret; + + if (state-flags CPUIDLE_FLAG_CHECK_BM) { + if (omap3_idle_bm_check()) { + BUG_ON(!dev-safe_state); + new_state = dev-safe_state; + goto select_state; + } + cx = cpuidle_get_statedata(state); + new_core_state = cx-core_state; + + /* Check if CORE is active, if yes, fallback to inactive */ + if (!pwrdm_can_idle(core_pd)) + new_core_state = PWRDM_POWER_INACTIVE; + + /* +* Prevent idle completely if CAM is active. +* CAM does not have wakeup capability in OMAP3. +*/ + cam_state = pwrdm_get_idle_state(cam_pd); + if (cam_state == PWRDM_POWER_ON) { + new_state = dev-safe_state; + goto select_state; + } + + /* +* Check if PER can idle or not. If we are not likely +* to idle, deny PER off. This prevents unnecessary +* context save/restore. +*/ + saved_per_state = pwrdm_read_next_pwrst(per_pd); + if (pwrdm_can_idle(per_pd)) { + per_state = saved_per_state; + /* +* Prevent PER off if CORE is active as this +* would disable PER wakeups completely +*/ + if (per_state == PWRDM_POWER_OFF + new_core_state PWRDM_POWER_RET) + per_state = PWRDM_POWER_RET; + + } else if (saved_per_state == PWRDM_POWER_OFF) + per_state = PWRDM_POWER_RET; + + /* +* If we are attempting CORE off, check if any other +* powerdomains are at retention or higher. CORE off causes +* chipwide reset which would reset these domains also. +*/ + if (new_core_state == PWRDM_POWER_OFF) { + dss_state = pwrdm_get_idle_state(dss_pd); + iva2_state = pwrdm_get_idle_state(iva2_pd); + sgx_state = pwrdm_get_idle_state(sgx_pd); + usb_state
[PATCHv4 4/8] OMAP3: CPUidle: Fixed support for ON / INACTIVE states
From: Tero Kristo tero.kri...@nokia.com New powerdomain code support for INACTIVE state removes the need to control clockdomains directly from cpuidle. Also, cpuidle state definitions can now directly support ON / INACTIVE simplifying the implementation. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 32 1 files changed, 4 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 1cfa5a6..4a81ef1 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -91,20 +91,6 @@ static int omap3_idle_bm_check(void) return 0; } -static int _cpuidle_allow_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_allow_idle(clkdm); - return 0; -} - -static int _cpuidle_deny_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_deny_idle(clkdm); - return 0; -} - /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -141,19 +127,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); - } - /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); - } - return_sleep_time: getnstimeofday(ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); @@ -246,8 +222,8 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[OMAP3_STATE_C2].threshold = cpuidle_params_table[OMAP3_STATE_C2].threshold; - omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; /* C3 . MPU CSWR + Core inactive */ @@ -261,7 +237,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; - omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; @@ -276,7 +252,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; - omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 1/8] OMAP3: Clockdomain: Added API for checking if HWSUP is enabled
From: Tero Kristo tero.kri...@nokia.com omap2_clkdm_get_hwsup(clkdm) can be used to check if automatic HW transitions for the domain are enabled or not. This is needed for the powerdomain code that adds support for INACTIVE state, as it needs to disable HWSUP on the fly for ON state, and re-enable it after returning to some other state. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 27 + arch/arm/plat-omap/include/plat/clockdomain.h |1 + 2 files changed, 28 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index dd285f0..728d1b0 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -472,6 +472,33 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } +/* + * omap2_clkdm_get_hwsup - get the hwsup idle transition bit + * @clkdm: struct clockdomain * + * + * Checks whether hardware is allowed to switch the clockdomain + * automatically into active or idle states. Returns 1 if yes, + * 0 otherwise. + */ +int omap2_clkdm_get_hwsup(struct clockdomain *clkdm) +{ + u32 v; + + if (cpu_is_omap24xx()) + v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; + else if (cpu_is_omap34xx()) + v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; + else + BUG(); + + if ((cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, CM_CLKSTCTRL) + clkdm-clktrctrl_mask) == + (v __ffs(clkdm-clktrctrl_mask))) + return 1; + + return 0; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/plat-omap/include/plat/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h index eb73482..9127459 100644 --- a/arch/arm/plat-omap/include/plat/clockdomain.h +++ b/arch/arm/plat-omap/include/plat/clockdomain.h @@ -99,6 +99,7 @@ int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), void *user); struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm); +int omap2_clkdm_get_hwsup(struct clockdomain *clkdm); void omap2_clkdm_allow_idle(struct clockdomain *clkdm); void omap2_clkdm_deny_idle(struct clockdomain *clkdm); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 2/8] OMAP: Powerdomains: Add support for INACTIVE state on pwrdm level
From: Tero Kristo tero.kri...@nokia.com Currently only ON, RET and OFF are supported, and ON is arguably broken as it allows the powerdomain to enter INACTIVE state unless idle is prevented. Now, pwrdm code prevents idle if ON is selected and hardware supervised mode for the underlying clockdomain is enabled, and also adds support for INACTIVE. This simplifies the control needed inside sleep code. This patch also requires caching of next power state inside powerdomain code, as INACTIVE is not directly supported by hardware. Next powerstate is thus now stored for each powerdomain in next_state. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/powerdomain.c | 37 + arch/arm/mach-omap2/powerdomains34xx.h| 18 ++-- arch/arm/plat-omap/include/plat/powerdomain.h |5 +++ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 26b3f3e..bdfbbea 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -110,8 +110,8 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev; - int state; + u8 prev; + u8 state; if (pwrdm == NULL) return -EINVAL; @@ -218,7 +218,9 @@ int pwrdm_register(struct powerdomain *pwrdm) pr_debug(powerdomain: registered %s\n, pwrdm-name); ret = 0; - + pwrdm-next_state = + prm_read_mod_bits_shift(pwrdm-prcm_offs, PM_PWSTCTRL, + OMAP_POWERSTATE_MASK); pr_unlock: write_unlock_irqrestore(pwrdm_rwlock, flags); @@ -699,19 +701,43 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) */ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) { + u8 prg_pwrst; + if (!pwrdm) return -EINVAL; + if (pwrdm-next_state == pwrst) + return 0; + if (!(pwrdm-pwrsts (1 pwrst))) return -EINVAL; pr_debug(powerdomain: setting next powerstate for %s to %0x\n, pwrdm-name, pwrst); + /* INACTIVE is reserved, so we program pwrdm as ON */ + if (pwrst == PWRDM_POWER_INACTIVE) + prg_pwrst = PWRDM_POWER_ON; + else + prg_pwrst = pwrst; + prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, -(pwrst OMAP_POWERSTATE_SHIFT), +(prg_pwrst OMAP_POWERSTATE_SHIFT), pwrdm-prcm_offs, PM_PWSTCTRL); + /* If next state is ON, prevent idle */ + if (pwrst == PWRDM_POWER_ON) { + if (omap2_clkdm_get_hwsup(pwrdm-pwrdm_clkdms[0])) { + omap2_clkdm_deny_idle(pwrdm-pwrdm_clkdms[0]); + pwrdm-hwsup_changed = 1; + } + } else if (pwrdm-hwsup_changed) { + omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); + pwrdm-hwsup_changed = 0; + } + + pwrdm-next_state = pwrst; + return 0; } @@ -728,8 +754,7 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; - return prm_read_mod_bits_shift(pwrdm-prcm_offs, PM_PWSTCTRL, - OMAP_POWERSTATE_MASK); + return pwrdm-next_state; } /** diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index 588f7e0..7a7d8d3 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -165,7 +165,7 @@ static struct powerdomain iva2_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, .wkdep_srcs = iva2_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks= 4, .pwrsts_mem_ret = { @@ -188,7 +188,7 @@ static struct powerdomain mpu_34xx_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_EN_MPU_SHIFT, .wkdep_srcs = mpu_34xx_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .flags= PWRDM_HAS_MPU_QUIRK, .banks= 1, @@ -207,7 +207,7 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0), - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .dep_bit
[PATCHv4 6/8] OMAP3: Clock: Added IDLEST definitions for SGX
From: Tero Kristo tero.kri...@nokia.com Added definitions for OMAP3430ES2_ST_SGX_SHIFT and OMAP3430ES2_ST_SGX_MASK as these were missing. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cm-regbits-34xx.h |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h index a76e835..d18da47 100644 --- a/arch/arm/mach-omap2/cm-regbits-34xx.h +++ b/arch/arm/mach-omap2/cm-regbits-34xx.h @@ -379,6 +379,10 @@ #define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT 1 #define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_MASK (1 1) +/* CM_IDLEST_SGX */ +#define OMAP3430ES2_ST_SGX_SHIFT 1 +#define OMAP3430ES2_ST_SGX_MASK(1 1) + /* CM_ICLKEN_SGX */ #define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT 0 #define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_MASK (1 0) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 3/8] OMAP3: PM: Added support for INACTIVE and ON states for powerdomains
From: Tero Kristo tero.kri...@nokia.com Previously omap_sram_idle() did not know about the difference between ON and INACTIVE states, which complicated the state handling in these cases. Now, the following changes are done in the idle logic: - Check for IO-chain arming is changed to reflect desired state (RET) - UART clocks will be disabled if we attempt to enter INACTIVE (this allows the state change to actually happen) Also, due to changes to pwrdm_set_next_pwrst() the behavior of set_pwrdm_state() is modified accordingly. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 29 ++--- 1 files changed, 14 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 190f25c..dceb18f 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -386,6 +386,7 @@ void omap_sram_idle(void) mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -452,9 +453,11 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } - /* Enable IO-PAD and IO-CHAIN wakeups */ - prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); - omap3_enable_io_chain(); + if (core_next_state = PWRDM_POWER_RET) { + /* Enable IO-PAD and IO-CHAIN wakeups */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); + } } omap3_intc_prepare_idle(); @@ -556,15 +559,13 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (core_next_state PWRDM_POWER_ON) { + if (core_next_state = PWRDM_POWER_RET) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } pwrdm_post_transition(); - - omap2_clkdm_allow_idle(mpu_pwrdm-pwrdm_clkdms[0]); } int omap3_can_sleep(void) @@ -582,7 +583,6 @@ int omap3_can_sleep(void) int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) { u32 cur_state; - int sleep_switch = 0; int ret = 0; if (pwrdm == NULL || IS_ERR(pwrdm)) @@ -598,12 +598,6 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) if (cur_state == state) return ret; - if (pwrdm_read_pwrst(pwrdm) PWRDM_POWER_ON) { - omap2_clkdm_wakeup(pwrdm-pwrdm_clkdms[0]); - sleep_switch = 1; - pwrdm_wait_transition(pwrdm); - } - ret = pwrdm_set_next_pwrst(pwrdm, state); if (ret) { printk(KERN_ERR Unable to set state of powerdomain: %s\n, @@ -611,8 +605,13 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) goto err; } - if (sleep_switch) { - omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); + cur_state = pwrdm_read_pwrst(pwrdm); + if (cur_state PWRDM_POWER_ON cur_state != state) { + /* Force wakeup */ + omap2_clkdm_wakeup(pwrdm-pwrdm_clkdms[0]); + pwrdm_wait_transition(pwrdm); + if (state PWRDM_POWER_ON) + omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 7/8] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clocks and idle status bits of the domain according to following rules: 1) functional clock check * get FCLK register content * ignore all clocks defined in idle_def.fclk_ignore * if any active functional clocks remain, domain can't idle 2) idle status check * get IDLEST register content * inverse it (any non-idle blocks are now as 1) * mask against idle_def.idlest_mask * if any bits remain high, domain can't idle These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 32 arch/arm/mach-omap2/clockdomains.h| 106 + arch/arm/mach-omap2/powerdomain.c | 25 ++ arch/arm/plat-omap/include/plat/clockdomain.h | 17 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 181 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 728d1b0..5665755 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -499,6 +499,38 @@ int omap2_clkdm_get_hwsup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-clk_reg_num; i++) { + u32 idlest, fclk; + + fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_FCLKEN + 4 * i); + if (fclk ~clkdm-idle_def[i].fclk_ignore) + return 0; + + idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_IDLEST + 4 * i); + if (~idlest clkdm-idle_def[i].idlest_mask) + return 0; + } + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index c4ee076..91efc60 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -167,6 +167,12 @@ static struct clockdomain iva2_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430_ST_IVA2, + }, + }, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -183,6 +189,12 @@ static struct clockdomain sgx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT, + }, + }, }; /* @@ -206,6 +218,57 @@ static struct clockdomain core_l3_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 3, + .idle_def = { + [0] = { + /* UARTs are controlled by idle loop so ignore */ + .fclk_ignore = OMAP3430_EN_UART2 | + OMAP3430_EN_UART1, + /* +* Reason for IDLEST ignores: +* - SDRC and OMAPCTRL controlled by HW +* - HSOTGUSB_IDLE bit is autoidled by HW +*/ + .idlest_mask = + OMAP3430ES2_ST_MMC3_MASK | + OMAP3430_ST_ICR_MASK | + OMAP3430_ST_AES2_MASK | + OMAP3430_ST_SHA12_MASK | + OMAP3430_ST_DES2_MASK | + OMAP3430_ST_MMC2_MASK | + OMAP3430_ST_MMC1_MASK
[PATCH] OMAP3: Serial: Improved sleep logic
From: Tero Kristo tero.kri...@nokia.com Only RX interrupt will now kick the sleep prevent timer. In addition, TX fifo status is checked before disabling clocks, this will prevent occasional garbage being printed on serial line. Smartidle is also disabled while entering idle if we have data in the transmit buffer, because having this enabled will prevent wakeups from the TX interrupt, and this causes pauses while sending large blocks of data. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/serial.c | 19 +++ 1 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 777e802..e11dfe9 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -317,7 +317,8 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart) if (!uart-clocked) return; - omap_uart_smart_idle_enable(uart, 1); + if (serial_read_reg(uart-p, UART_LSR) UART_LSR_TEMT) + omap_uart_smart_idle_enable(uart, 1); uart-can_sleep = 1; del_timer(uart-timer); } @@ -335,7 +336,11 @@ void omap_uart_prepare_idle(int num) list_for_each_entry(uart, uart_list, node) { if (num == uart-num uart-can_sleep) { - omap_uart_disable_clocks(uart); + if (serial_read_reg(uart-p, UART_LSR) + UART_LSR_TEMT) + omap_uart_disable_clocks(uart); + else + omap_uart_smart_idle_enable(uart, 0); return; } } @@ -407,8 +412,14 @@ int omap_uart_can_sleep(void) static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) { struct omap_uart_state *uart = dev_id; + u8 lsr; - omap_uart_block_sleep(uart); + lsr = serial_read_reg(uart-p, UART_LSR); + /* Check for receive interrupt */ + if (lsr UART_LSR_DR) + omap_uart_block_sleep(uart); + if (lsr UART_LSR_TEMT uart-can_sleep) + omap_uart_smart_idle_enable(uart, 1); return IRQ_NONE; } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 0/9] Idlestatus patches
From: Tero Kristo tero.kri...@nokia.com Improvements compared to previous version: - Removed hacks from generic powerdomain code, instead added support routines for OMAP3, which are used by pm34xx.c and cpuidle34xx.c, these support routines only touch mpu, core and neon powerdomains - Bug fix: comparison in cpuidle fallback loop was incorrect - Changed peripheral can_idle checks into direct checks for the current power state - Fixed support for off-mode enabling as part of this set, cpuidle now selects proper state when off-mode is disabled - Added support for INACTIVE states for suspend code (mpu, core, neon only) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 2/9] OMAP3: PM: Added support for INACTIVE and ON states in omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Previously omap_sram_idle() did not know about the difference between ON and INACTIVE states, which complicated the state handling in these cases. Now, the following changes are done in the idle logic: - Check for IO-chain arming is changed to reflect desired state (RET) - UART clocks will be disabled if we attempt to enter INACTIVE (this allows the state change to actually happen) Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 23 --- 1 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 256ed18..fa9ff9b 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -383,9 +383,10 @@ void omap_sram_idle(void) pwrdm_clear_all_prev_pwrst(core_pwrdm); pwrdm_clear_all_prev_pwrst(per_pwrdm); - mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); + mpu_next_state = omap3_pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -403,11 +404,11 @@ void omap_sram_idle(void) /* NEON control */ if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) - pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); + omap3_pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); /* PER */ - per_next_state = pwrdm_read_next_pwrst(per_pwrdm); - core_next_state = pwrdm_read_next_pwrst(core_pwrdm); + per_next_state = omap3_pwrdm_read_next_pwrst(per_pwrdm); + core_next_state = omap3_pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state PWRDM_POWER_ON) { omap2_gpio_prepare_for_idle(per_next_state); if (per_next_state == PWRDM_POWER_OFF) { @@ -452,9 +453,11 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } - /* Enable IO-PAD and IO-CHAIN wakeups */ - prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); - omap3_enable_io_chain(); + if (core_next_state = PWRDM_POWER_RET) { + /* Enable IO-PAD and IO-CHAIN wakeups */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); + } } omap3_intc_prepare_idle(); @@ -556,15 +559,13 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (core_next_state PWRDM_POWER_ON) { + if (core_next_state = PWRDM_POWER_RET) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } pwrdm_post_transition(); - - omap2_clkdm_allow_idle(mpu_pwrdm-pwrdm_clkdms[0]); } int omap3_can_sleep(void) @@ -730,7 +731,7 @@ static int omap3_pm_suspend(void) /* Read current next_pwrsts */ list_for_each_entry(pwrst, pwrst_list, node) - pwrst-saved_state = pwrdm_read_next_pwrst(pwrst-pwrdm); + pwrst-saved_state = omap3_pwrdm_read_next_pwrst(pwrst-pwrdm); /* Set ones wanted by suspend */ list_for_each_entry(pwrst, pwrst_list, node) { if (set_pwrdm_state(pwrst-pwrdm, pwrst-next_state)) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 1/9] OMAP3: PM: Added support functions for omap3 pwrdm handling
From: Tero Kristo tero.kri...@nokia.com Added omap3_pwrdm_set_next_pwrst and omap3_pwrdm_read_next_pwrst. These functions add support for INACTIVE and ON states to the standard OMAP powerdomain functions, and add caching logic for the next state. These functions are used in subsequent patches to simplify the logic of the idle loop. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm.h |2 + arch/arm/mach-omap2/pm34xx.c | 60 +- 2 files changed, 61 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 75aa685..1d9a740 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -67,6 +67,8 @@ static inline void omap3_pm_init_vc(struct prm_setup_vc *setup_vc) extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); +extern int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); +extern int omap3_pwrdm_read_next_pwrst(struct powerdomain *pwrdm); extern u32 wakeup_timer_seconds; extern struct omap_dm_timer *gptimer_wakeup; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 190f25c..256ed18 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -576,6 +576,64 @@ int omap3_can_sleep(void) return 1; } +struct powerdomain_data { + u8 next_state; + u8 init_done; +}; + +static struct powerdomain_data mpu_pwrdm_data; +static struct powerdomain_data core_pwrdm_data; +static struct powerdomain_data neon_pwrdm_data; + +static struct powerdomain_data *get_pwrdm_data(struct powerdomain *pwrdm) +{ + if (pwrdm == mpu_pwrdm) + return mpu_pwrdm_data; + else if (pwrdm == core_pwrdm) + return core_pwrdm_data; + else if (pwrdm == neon_pwrdm) + return neon_pwrdm_data; + return NULL; +} + +int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) +{ + struct powerdomain_data *data = get_pwrdm_data(pwrdm); + u8 prg_pwrst; + + if (!data) + return pwrdm_set_next_pwrst(pwrdm, pwrst); + + if (!data-init_done) + data-init_done = 1; + else if (data-next_state == pwrst) + return 0; + + if (pwrst == PWRDM_POWER_INACTIVE) + prg_pwrst = PWRDM_POWER_ON; + else + prg_pwrst = pwrst; + + pwrdm_set_next_pwrst(pwrdm, prg_pwrst); + + if (pwrst == PWRDM_POWER_ON) + omap2_clkdm_deny_idle(pwrdm-pwrdm_clkdms[0]); + else + omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); + + data-next_state = pwrst; + return 0; +} + +int omap3_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) +{ + struct powerdomain_data *data = get_pwrdm_data(pwrdm); + + if (!data || !data-init_done) + return pwrdm_read_next_pwrst(pwrdm); + return data-next_state; +} + /* This sets pwrdm state (other than mpu core. Currently only ON * RET are supported. Function is assuming that clkdm doesn't have * hw_sup mode enabled. */ @@ -604,7 +662,7 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) pwrdm_wait_transition(pwrdm); } - ret = pwrdm_set_next_pwrst(pwrdm, state); + ret = omap3_pwrdm_set_next_pwrst(pwrdm, state); if (ret) { printk(KERN_ERR Unable to set state of powerdomain: %s\n, pwrdm-name); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 6/9] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clocks and idle status bits of the domain according to following rules: 1) functional clock check * get FCLK register content * ignore all clocks defined in idle_def.fclk_ignore * if any active functional clocks remain, domain can't idle 2) idle status check * get IDLEST register content * inverse it (any non-idle blocks are now as 1) * mask against idle_def.idlest_mask * if any bits remain high, domain can't idle These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 32 arch/arm/mach-omap2/clockdomains.h| 106 + arch/arm/mach-omap2/powerdomain.c | 25 ++ arch/arm/plat-omap/include/plat/clockdomain.h | 17 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 181 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index dd285f0..63020d4 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -472,6 +472,38 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-clk_reg_num; i++) { + u32 idlest, fclk; + + fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_FCLKEN + 4 * i); + if (fclk ~clkdm-idle_def[i].fclk_ignore) + return 0; + + idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_IDLEST + 4 * i); + if (~idlest clkdm-idle_def[i].idlest_mask) + return 0; + } + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index c4ee076..65e2f69 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -167,6 +167,12 @@ static struct clockdomain iva2_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430_ST_IVA2, + }, + }, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -183,6 +189,12 @@ static struct clockdomain sgx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT, + }, + }, }; /* @@ -206,6 +218,57 @@ static struct clockdomain core_l3_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 3, + .idle_def = { + [0] = { + /* UARTs are controlled by idle loop so ignore */ + .fclk_ignore = OMAP3430_EN_UART2 | + OMAP3430_EN_UART1, + /* +* Reason for IDLEST ignores: +* - SDRC and OMAPCTRL controlled by HW +* - HSOTGUSB_IDLE bit is autoidled by HW +* - MAILBOX is controlled by HW +*/ + .idlest_mask = + OMAP3430ES2_ST_MMC3_MASK | + OMAP3430_ST_ICR_MASK | + OMAP3430_ST_AES2_MASK | + OMAP3430_ST_SHA12_MASK | + OMAP3430_ST_DES2_MASK | + OMAP3430_ST_MMC2_MASK
[PATCHv5 3/9] OMAP3: CPUidle: Fixed support for ON / INACTIVE states
From: Tero Kristo tero.kri...@nokia.com New powerdomain support code for INACTIVE state removes the need to control clockdomains directly from cpuidle. Also, cpuidle state definitions can now directly support ON / INACTIVE simplifying the implementation. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 36 ++-- 1 files changed, 6 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 1cfa5a6..86f580b 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -91,20 +91,6 @@ static int omap3_idle_bm_check(void) return 0; } -static int _cpuidle_allow_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_allow_idle(clkdm); - return 0; -} - -static int _cpuidle_deny_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_deny_idle(clkdm); - return 0; -} - /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -135,25 +121,15 @@ static int omap3_enter_idle(struct cpuidle_device *dev, core_state = PWRDM_POWER_RET; } - pwrdm_set_next_pwrst(mpu_pd, mpu_state); - pwrdm_set_next_pwrst(core_pd, core_state); + omap3_pwrdm_set_next_pwrst(mpu_pd, mpu_state); + omap3_pwrdm_set_next_pwrst(core_pd, core_state); if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); - } - /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); - } - return_sleep_time: getnstimeofday(ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); @@ -246,8 +222,8 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[OMAP3_STATE_C2].threshold = cpuidle_params_table[OMAP3_STATE_C2].threshold; - omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; /* C3 . MPU CSWR + Core inactive */ @@ -261,7 +237,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; - omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; @@ -276,7 +252,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; - omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 5/9] OMAP3: Clock: Added IDLEST definitions for SGX
From: Tero Kristo tero.kri...@nokia.com Added definitions for OMAP3430ES2_ST_SGX_SHIFT and OMAP3430ES2_ST_SGX_MASK as these were missing. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cm-regbits-34xx.h |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h index a76e835..d18da47 100644 --- a/arch/arm/mach-omap2/cm-regbits-34xx.h +++ b/arch/arm/mach-omap2/cm-regbits-34xx.h @@ -379,6 +379,10 @@ #define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT 1 #define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_MASK (1 1) +/* CM_IDLEST_SGX */ +#define OMAP3430ES2_ST_SGX_SHIFT 1 +#define OMAP3430ES2_ST_SGX_MASK(1 1) + /* CM_ICLKEN_SGX */ #define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT 0 #define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_MASK (1 0) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 7/9] OMAP3: CPUidle: Added peripheral pwrdm checks into bm check
From: Tero Kristo tero.kri...@nokia.com Following checks are made (and their reasoning): - If CAM domain is active, prevent idle completely * CAM pwrdm does not have HW wakeup capability - If PER is likely to remain on, prevent PER off * Saves on unnecessary context save/restore - If CORE domain is active, prevent PER off-mode * PER off in this case would prevent wakeups from PER completely - Only allow CORE off, if all peripheral domains are off * CORE off will cause a chipwide reset Also, enabled CHECK_BM flag for C2, as this is needed for the camera case. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 102 ++--- 1 files changed, 95 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 86f580b..38bd70c 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -58,7 +58,8 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd; +static struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd; +static struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd; /* * The latencies/thresholds for various C states have @@ -153,14 +154,94 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; - - if ((state-flags CPUIDLE_FLAG_CHECK_BM) omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); - new_state = dev-safe_state; + u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; + u32 iva2_state, sgx_state, dss_state, new_core_state; + struct omap3_processor_cx *cx; + int ret; + + if (state-flags CPUIDLE_FLAG_CHECK_BM) { + if (omap3_idle_bm_check()) { + BUG_ON(!dev-safe_state); + new_state = dev-safe_state; + goto select_state; + } + cx = cpuidle_get_statedata(state); + new_core_state = cx-core_state; + + /* Check if CORE is active, if yes, fallback to inactive */ + if (!pwrdm_can_idle(core_pd)) + new_core_state = PWRDM_POWER_INACTIVE; + + /* +* Prevent idle completely 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) { + new_state = dev-safe_state; + goto select_state; + } + + /* +* Check if PER can idle or not. If we are not likely +* to idle, deny PER off. This prevents unnecessary +* context save/restore. +*/ + saved_per_state = omap3_pwrdm_read_next_pwrst(per_pd); + if (pwrdm_can_idle(per_pd)) { + per_state = saved_per_state; + /* +* Prevent PER off if CORE is active as this +* would disable PER wakeups completely +*/ + if (per_state == PWRDM_POWER_OFF + new_core_state PWRDM_POWER_RET) + per_state = PWRDM_POWER_RET; + + } else if (saved_per_state == PWRDM_POWER_OFF) + per_state = PWRDM_POWER_RET; + + /* +* If we are attempting CORE off, check if any other +* powerdomains are at retention or higher. CORE off causes +* chipwide reset which would reset these domains also. +*/ + if (new_core_state == PWRDM_POWER_OFF) { + dss_state = pwrdm_read_pwrst(dss_pd); + iva2_state = pwrdm_read_pwrst(iva2_pd); + sgx_state = pwrdm_read_pwrst(sgx_pd); + usb_state = pwrdm_read_pwrst(usb_pd); + + if (cam_state PWRDM_POWER_OFF || + dss_state PWRDM_POWER_OFF || + iva2_state PWRDM_POWER_OFF || + per_state PWRDM_POWER_OFF || + sgx_state PWRDM_POWER_OFF || + usb_state PWRDM_POWER_OFF) + new_core_state = PWRDM_POWER_RET; + } + + /* Fallback to new target core state */ + while (cx-core_state new_core_state) { + state--; + cx = cpuidle_get_statedata(state); + } + new_state = state; + + /* Are we changing PER target
[PATCHv5 9/9] OMAP3: PM: Added support for suspending to INACTIVE state
From: Tero Kristo tero.kri...@nokia.com With the new support functions this is now possible. Suspending to INACTIVE is useful for testing purposes. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 11 ++- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 7946b70..b0911f2 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -633,11 +633,12 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) if (pwrdm == NULL || IS_ERR(pwrdm)) return -EINVAL; - while (!(pwrdm-pwrsts (1 state))) { - if (state == PWRDM_POWER_OFF) - return ret; - state--; - } + if (state != PWRDM_POWER_INACTIVE) + while (!(pwrdm-pwrsts (1 state))) { + if (state == PWRDM_POWER_OFF) + return ret; + state--; + } cur_state = pwrdm_read_next_pwrst(pwrdm); if (cur_state == state) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 4/9] OMAP3: PM: Removed pwrdm state hacking from omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Following hacks will be moved inside cpuidle in subsequent patch: - CAM domain prevents idle completely - PER should not go OFF if core remains active This simplifies the design and allows cpuidle to keep better track of which power states system will actually enter. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 19 ++- 1 files changed, 2 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index fa9ff9b..7946b70 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -93,7 +93,6 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; -static struct powerdomain *cam_pwrdm; static struct prm_setup_vc prm_setup = { .clksetup = 0xff, @@ -373,7 +372,6 @@ void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -411,20 +409,11 @@ void omap_sram_idle(void) core_next_state = omap3_pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state PWRDM_POWER_ON) { omap2_gpio_prepare_for_idle(per_next_state); - if (per_next_state == PWRDM_POWER_OFF) { - if (core_next_state == PWRDM_POWER_ON) { - per_next_state = PWRDM_POWER_RET; - pwrdm_set_next_pwrst(per_pwrdm, per_next_state); - per_state_modified = 1; - } else - omap3_per_save_context(); - } + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); omap_uart_prepare_idle(2); } - if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) - omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* * Disable smartreflex before entering WFI. * Only needed if we are going to enter retention or off. @@ -554,8 +543,6 @@ void omap_sram_idle(void) } omap2_gpio_resume_after_idle(); omap_uart_resume_idle(2); - if (per_state_modified) - pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -564,7 +551,6 @@ void omap_sram_idle(void) omap3_disable_io_chain(); } - pwrdm_post_transition(); } @@ -1235,7 +1221,6 @@ static 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); omap_push_sram_idle(); #ifdef CONFIG_SUSPEND -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 8/9] OMAP3: CPUidle: Fixed off-mode support to fall-back to proper C state
From: Tero Kristo tero.kri...@nokia.com If off-mode is disabled, cpuidle now falls back to proper C state. Previously the state was just simply hacked inside omap3_enter_idle which resulted in wrong state residencies to be reported. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 22 -- 1 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 38bd70c..dbb7315 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -115,13 +115,6 @@ static int omap3_enter_idle(struct cpuidle_device *dev, local_irq_disable(); local_fiq_disable(); - if (!enable_off_mode) { - if (mpu_state PWRDM_POWER_RET) - mpu_state = PWRDM_POWER_RET; - if (core_state PWRDM_POWER_RET) - core_state = PWRDM_POWER_RET; - } - omap3_pwrdm_set_next_pwrst(mpu_pd, mpu_state); omap3_pwrdm_set_next_pwrst(core_pd, core_state); @@ -155,7 +148,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, { struct cpuidle_state *new_state = state; u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; - u32 iva2_state, sgx_state, dss_state, new_core_state; + u32 iva2_state, sgx_state, dss_state, new_core_state, new_mpu_state; struct omap3_processor_cx *cx; int ret; @@ -167,6 +160,14 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, } cx = cpuidle_get_statedata(state); new_core_state = cx-core_state; + new_mpu_state = cx-mpu_state; + + if (!enable_off_mode) { + if (new_mpu_state PWRDM_POWER_RET) + new_mpu_state = PWRDM_POWER_RET; + if (new_core_state PWRDM_POWER_RET) + new_core_state = PWRDM_POWER_RET; + } /* Check if CORE is active, if yes, fallback to inactive */ if (!pwrdm_can_idle(core_pd)) @@ -221,8 +222,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, new_core_state = PWRDM_POWER_RET; } - /* Fallback to new target core state */ - while (cx-core_state new_core_state) { + /* Fallback to new target core/mpu state */ + while (cx-core_state new_core_state || + cx-mpu_state new_mpu_state) { state--; cx = cpuidle_get_statedata(state); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] OMAP3: Serial: Improved sleep logic
From: Tero Kristo tero.kri...@nokia.com This patch contains following improvements: - Only RX interrupt will now kick the sleep prevent timer - TX fifo status is checked before disabling clocks, this will prevent on-going transmission to be cut - Smartidle is disabled while entering idle if we have data in the transmit buffer because having this enabled would prevent wakeups from the TX interrupt and this would cause pauses while sending large blocks of data - Sleep prevent timer is changed to use ktime_get() instead of a jiffy timer as jiffy timers are not valid within idle loop (tick scheduler is stopped) - RX and TX fifos are cleared when clocks are enabled, this will purge the first character from RX fifo, which is most likely garbage Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/serial.c | 70 +++--- 1 files changed, 45 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 837b347..d7d96ba 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -23,12 +23,15 @@ #include linux/serial_reg.h #include linux/clk.h #include linux/io.h +#include linux/delay.h #include plat/common.h #include plat/board.h #include plat/clock.h #include plat/control.h +#include asm/div64.h + #include prm.h #include pm.h #include prm-regbits-34xx.h @@ -36,13 +39,13 @@ #define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV0x52 #define UART_OMAP_WER 0x17/* Wake-up enable register */ -#define DEFAULT_TIMEOUT (5 * HZ) +#define DEFAULT_TIMEOUT (5LL * NSEC_PER_SEC) struct omap_uart_state { int num; int can_sleep; - struct timer_list timer; - u32 timeout; + ktime_t expire_time; + u64 timeout; void __iomem *wk_st; void __iomem *wk_en; @@ -231,6 +234,9 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) clk_enable(uart-fck); uart-clocked = 1; omap_uart_restore_context(uart); + + /* Clear RX and TX fifos, as they contain garbage at this point */ + serial_write_reg(uart-p, UART_FCR, 0xa7); } #ifdef CONFIG_PM @@ -302,9 +308,7 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) omap_uart_smart_idle_enable(uart, 0); uart-can_sleep = 0; if (uart-timeout) - mod_timer(uart-timer, jiffies + uart-timeout); - else - del_timer(uart-timer); + uart-expire_time = ktime_add_ns(ktime_get(), uart-timeout); } static void omap_uart_allow_sleep(struct omap_uart_state *uart) @@ -317,25 +321,28 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart) if (!uart-clocked) return; - omap_uart_smart_idle_enable(uart, 1); + if (serial_read_reg(uart-p, UART_LSR) UART_LSR_TEMT) + omap_uart_smart_idle_enable(uart, 1); uart-can_sleep = 1; - del_timer(uart-timer); -} - -static void omap_uart_idle_timer(unsigned long data) -{ - struct omap_uart_state *uart = (struct omap_uart_state *)data; - - omap_uart_allow_sleep(uart); } void omap_uart_prepare_idle(int num) { struct omap_uart_state *uart; + ktime_t t; list_for_each_entry(uart, uart_list, node) { + if (num == uart-num !uart-can_sleep) { + t = ktime_get(); + if (t.tv64 uart-expire_time.tv64) + uart-can_sleep = 1; + } if (num == uart-num uart-can_sleep) { - omap_uart_disable_clocks(uart); + if (serial_read_reg(uart-p, UART_LSR) + UART_LSR_TEMT) + omap_uart_disable_clocks(uart); + else + omap_uart_smart_idle_enable(uart, 0); return; } } @@ -360,6 +367,7 @@ void omap_uart_resume_idle(int num) /* Check for normal UART wakeup */ if (__raw_readl(uart-wk_st) uart-wk_mask) omap_uart_block_sleep(uart); + return; } } @@ -407,8 +415,14 @@ int omap_uart_can_sleep(void) static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) { struct omap_uart_state *uart = dev_id; + u8 lsr; - omap_uart_block_sleep(uart); + lsr = serial_read_reg(uart-p, UART_LSR); + /* Check for receive interrupt */ + if (lsr UART_LSR_DR) + omap_uart_block_sleep(uart); + if (lsr UART_LSR_TEMT uart-can_sleep) + omap_uart_smart_idle_enable(uart, 1); return IRQ_NONE; } @@ -420,9 +434,9 @@ static void omap_uart_idle_init(struct omap_uart_state *uart) uart-can_sleep = 0; uart-timeout
[PATCHv3] OMAP3: Serial: Improved sleep logic
From: Tero Kristo tero.kri...@nokia.com This patch contains following improvements: - Only RX interrupt will now kick the sleep prevent timer - TX fifo status is checked before disabling clocks, this will prevent on-going transmission to be cut - Smartidle is disabled while entering idle if we have data in the transmit buffer because having this enabled would prevent wakeups from the TX interrupt and this would cause pauses while sending large blocks of data - Sleep prevent timer is changed to use ktime_get() instead of a jiffy timer as jiffy timers are not valid within idle loop (tick scheduler is stopped) - Added RX ignore timer for ignoring the first character received during first millisecond of wakeup, this prevents garbage character to be received in low sleep states Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/serial.c | 81 - 1 files changed, 55 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 837b347..75ce549 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -23,12 +23,15 @@ #include linux/serial_reg.h #include linux/clk.h #include linux/io.h +#include linux/delay.h #include plat/common.h #include plat/board.h #include plat/clock.h #include plat/control.h +#include asm/div64.h + #include prm.h #include pm.h #include prm-regbits-34xx.h @@ -36,13 +39,14 @@ #define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV0x52 #define UART_OMAP_WER 0x17/* Wake-up enable register */ -#define DEFAULT_TIMEOUT (5 * HZ) +#define DEFAULT_TIMEOUT (5LL * NSEC_PER_SEC) struct omap_uart_state { int num; int can_sleep; - struct timer_list timer; - u32 timeout; + ktime_t expire_time; + ktime_t garbage_time; + u64 timeout; void __iomem *wk_st; void __iomem *wk_en; @@ -231,6 +235,9 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) clk_enable(uart-fck); uart-clocked = 1; omap_uart_restore_context(uart); + + /* Set up garbage timer to ignore RX during first 1ms */ + uart-garbage_time = ktime_add_ns(ktime_get(), NSEC_PER_MSEC); } #ifdef CONFIG_PM @@ -302,9 +309,7 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) omap_uart_smart_idle_enable(uart, 0); uart-can_sleep = 0; if (uart-timeout) - mod_timer(uart-timer, jiffies + uart-timeout); - else - del_timer(uart-timer); + uart-expire_time = ktime_add_ns(ktime_get(), uart-timeout); } static void omap_uart_allow_sleep(struct omap_uart_state *uart) @@ -317,25 +322,28 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart) if (!uart-clocked) return; - omap_uart_smart_idle_enable(uart, 1); + if (serial_read_reg(uart-p, UART_LSR) UART_LSR_TEMT) + omap_uart_smart_idle_enable(uart, 1); uart-can_sleep = 1; - del_timer(uart-timer); -} - -static void omap_uart_idle_timer(unsigned long data) -{ - struct omap_uart_state *uart = (struct omap_uart_state *)data; - - omap_uart_allow_sleep(uart); } void omap_uart_prepare_idle(int num) { struct omap_uart_state *uart; + ktime_t t; list_for_each_entry(uart, uart_list, node) { + if (num == uart-num !uart-can_sleep) { + t = ktime_get(); + if (t.tv64 uart-expire_time.tv64) + uart-can_sleep = 1; + } if (num == uart-num uart-can_sleep) { - omap_uart_disable_clocks(uart); + if (serial_read_reg(uart-p, UART_LSR) + UART_LSR_TEMT) + omap_uart_disable_clocks(uart); + else + omap_uart_smart_idle_enable(uart, 0); return; } } @@ -360,6 +368,7 @@ void omap_uart_resume_idle(int num) /* Check for normal UART wakeup */ if (__raw_readl(uart-wk_st) uart-wk_mask) omap_uart_block_sleep(uart); + return; } } @@ -407,10 +416,24 @@ int omap_uart_can_sleep(void) static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) { struct omap_uart_state *uart = dev_id; + u8 lsr; + int ret = IRQ_NONE; - omap_uart_block_sleep(uart); + lsr = serial_read_reg(uart-p, UART_LSR); + /* Check for receive interrupt */ + if (lsr UART_LSR_DR) { + omap_uart_block_sleep(uart); + if (uart-garbage_time.tv64 + ktime_get().tv64 uart-garbage_time.tv64) { + serial_read_reg(uart-p, UART_RX
[PATCHv4] OMAP3: Serial: Improved sleep logic
From: Tero Kristo tero.kri...@nokia.com This patch contains following improvements: - Only RX interrupt will now kick the sleep prevent timer - TX fifo status is checked before disabling clocks, this will prevent on-going transmission to be cut - Smartidle is now enabled/disabled only while switching clocks, as having smartidle enabled while RX/TX prevents any wakeups from being received from UART module - Sleep prevent timer is changed to use ktime_get() instead of a jiffy timer as jiffy timers are not valid within idle loop (tick scheduler is stopped) - Added RX ignore timer for ignoring the first character received during first millisecond of wakeup, this prevents garbage character to be receive in low sleep states Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/serial.c | 79 +++-- 1 files changed, 52 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 5f3035e..4be9ace 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -29,6 +29,8 @@ #include plat/clock.h #include plat/control.h +#include asm/div64.h + #include prm.h #include pm.h #include prm-regbits-34xx.h @@ -42,13 +44,14 @@ * disabled via sysfs. This also causes that any deeper omap sleep states are * blocked. */ -#define DEFAULT_TIMEOUT 0 +#define DEFAULT_TIMEOUT (0LL * NSEC_PER_SEC) struct omap_uart_state { int num; int can_sleep; - struct timer_list timer; - u32 timeout; + ktime_t expire_time; + ktime_t garbage_time; + u64 timeout; void __iomem *wk_st; void __iomem *wk_en; @@ -243,6 +246,9 @@ static inline void omap_uart_save_context(struct omap_uart_state *uart) {} static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} #endif /* CONFIG_PM CONFIG_ARCH_OMAP3 */ +static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, + int enable); + static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) { if (uart-clocked) @@ -250,8 +256,12 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) clk_enable(uart-ick); clk_enable(uart-fck); + omap_uart_smart_idle_enable(uart, 0); uart-clocked = 1; omap_uart_restore_context(uart); + + /* Set up garbage timer to ignore RX during first 1ms */ + uart-garbage_time = ktime_add_ns(ktime_get(), NSEC_PER_MSEC); } #ifdef CONFIG_PM @@ -263,6 +273,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) omap_uart_save_context(uart); uart-clocked = 0; + omap_uart_smart_idle_enable(uart, 1); clk_disable(uart-ick); clk_disable(uart-fck); } @@ -320,12 +331,9 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) { omap_uart_enable_clocks(uart); - omap_uart_smart_idle_enable(uart, 0); uart-can_sleep = 0; if (uart-timeout) - mod_timer(uart-timer, jiffies + uart-timeout); - else - del_timer(uart-timer); + uart-expire_time = ktime_add_ns(ktime_get(), uart-timeout); } static void omap_uart_allow_sleep(struct omap_uart_state *uart) @@ -338,16 +346,7 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart) if (!uart-clocked) return; - omap_uart_smart_idle_enable(uart, 1); uart-can_sleep = 1; - del_timer(uart-timer); -} - -static void omap_uart_idle_timer(unsigned long data) -{ - struct omap_uart_state *uart = (struct omap_uart_state *)data; - - omap_uart_allow_sleep(uart); } void omap_uart_prepare_idle(int num) @@ -355,8 +354,14 @@ void omap_uart_prepare_idle(int num) struct omap_uart_state *uart; list_for_each_entry(uart, uart_list, node) { + if (num == uart-num !uart-can_sleep uart-timeout) + if (ktime_get().tv64 uart-expire_time.tv64) + uart-can_sleep = 1; + if (num == uart-num uart-can_sleep) { - omap_uart_disable_clocks(uart); + if (serial_read_reg(uart-p, UART_LSR) + UART_LSR_TEMT) + omap_uart_disable_clocks(uart); return; } } @@ -404,6 +409,10 @@ int omap_uart_can_sleep(void) if (!uart-clocked) continue; + if (!uart-can_sleep uart-timeout + ktime_get().tv64 uart-expire_time.tv64) + uart-can_sleep = 1; + if (!uart-can_sleep) { can_sleep = 0; continue; @@ -428,10 +437,22 @@ int omap_uart_can_sleep(void) static irqreturn_t omap_uart_interrupt(int irq, void *dev_id
[PATCHv6 2/9] OMAP3: PM: Added support for INACTIVE and ON states in omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Previously omap_sram_idle() did not know about the difference between ON and INACTIVE states, which complicated the state handling in these cases. Now, the following changes are done in the idle logic: - Check for IO-chain arming is changed to reflect desired state (RET) - UART clocks will be disabled if we attempt to enter INACTIVE (this allows the state change to actually happen) Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 23 --- 1 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index f20d3d8..c2d80fc 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -383,9 +383,10 @@ void omap_sram_idle(void) pwrdm_clear_all_prev_pwrst(core_pwrdm); pwrdm_clear_all_prev_pwrst(per_pwrdm); - mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); + mpu_next_state = omap3_pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -403,11 +404,11 @@ void omap_sram_idle(void) /* NEON control */ if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) - pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); + omap3_pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); /* PER */ - per_next_state = pwrdm_read_next_pwrst(per_pwrdm); - core_next_state = pwrdm_read_next_pwrst(core_pwrdm); + per_next_state = omap3_pwrdm_read_next_pwrst(per_pwrdm); + core_next_state = omap3_pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state PWRDM_POWER_ON) { omap2_gpio_prepare_for_idle(per_next_state); if (per_next_state == PWRDM_POWER_OFF) { @@ -452,9 +453,11 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } - /* Enable IO-PAD and IO-CHAIN wakeups */ - prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); - omap3_enable_io_chain(); + if (core_next_state = PWRDM_POWER_RET) { + /* Enable IO-PAD and IO-CHAIN wakeups */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); + } } omap3_intc_prepare_idle(); @@ -556,15 +559,13 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (core_next_state PWRDM_POWER_ON) { + if (core_next_state = PWRDM_POWER_RET) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } pwrdm_post_transition(); - - omap2_clkdm_allow_idle(mpu_pwrdm-pwrdm_clkdms[0]); } int omap3_can_sleep(void) @@ -730,7 +731,7 @@ static int omap3_pm_suspend(void) /* Read current next_pwrsts */ list_for_each_entry(pwrst, pwrst_list, node) - pwrst-saved_state = pwrdm_read_next_pwrst(pwrst-pwrdm); + pwrst-saved_state = omap3_pwrdm_read_next_pwrst(pwrst-pwrdm); /* Set ones wanted by suspend */ list_for_each_entry(pwrst, pwrst_list, node) { if (set_pwrdm_state(pwrst-pwrdm, pwrst-next_state)) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv6 3/9] OMAP3: CPUidle: Fixed support for ON / INACTIVE states
From: Tero Kristo tero.kri...@nokia.com New powerdomain support code for INACTIVE state removes the need to control clockdomains directly from cpuidle. Also, cpuidle state definitions can now directly support ON / INACTIVE simplifying the implementation. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 36 ++-- 1 files changed, 6 insertions(+), 30 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 1cfa5a6..86f580b 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -91,20 +91,6 @@ static int omap3_idle_bm_check(void) return 0; } -static int _cpuidle_allow_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_allow_idle(clkdm); - return 0; -} - -static int _cpuidle_deny_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_deny_idle(clkdm); - return 0; -} - /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -135,25 +121,15 @@ static int omap3_enter_idle(struct cpuidle_device *dev, core_state = PWRDM_POWER_RET; } - pwrdm_set_next_pwrst(mpu_pd, mpu_state); - pwrdm_set_next_pwrst(core_pd, core_state); + omap3_pwrdm_set_next_pwrst(mpu_pd, mpu_state); + omap3_pwrdm_set_next_pwrst(core_pd, core_state); if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); - } - /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); - } - return_sleep_time: getnstimeofday(ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); @@ -246,8 +222,8 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[OMAP3_STATE_C2].threshold = cpuidle_params_table[OMAP3_STATE_C2].threshold; - omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; /* C3 . MPU CSWR + Core inactive */ @@ -261,7 +237,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; - omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; @@ -276,7 +252,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; - omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv6 5/9] OMAP3: Clock: Added IDLEST definitions for SGX
From: Tero Kristo tero.kri...@nokia.com Added definitions for OMAP3430ES2_ST_SGX_SHIFT and OMAP3430ES2_ST_SGX_MASK as these were missing. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cm-regbits-34xx.h |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h index 6923deb..60f9b16 100644 --- a/arch/arm/mach-omap2/cm-regbits-34xx.h +++ b/arch/arm/mach-omap2/cm-regbits-34xx.h @@ -379,6 +379,10 @@ #define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT 1 #define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_MASK (1 1) +/* CM_IDLEST_SGX */ +#define OMAP3430ES2_ST_SGX_SHIFT 1 +#define OMAP3430ES2_ST_SGX_MASK(1 1) + /* CM_ICLKEN_SGX */ #define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT 0 #define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_MASK (1 0) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv6 4/9] OMAP3: PM: Removed pwrdm state hacking from omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Following hacks will be moved inside cpuidle in subsequent patch: - CAM domain prevents idle completely - PER should not go OFF if core remains active This simplifies the design and allows cpuidle to keep better track of which power states system will actually enter. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 19 ++- 1 files changed, 2 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index c2d80fc..cdbedcf 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -93,7 +93,6 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; -static struct powerdomain *cam_pwrdm; static struct prm_setup_vc prm_setup = { .clksetup = 0xff, @@ -373,7 +372,6 @@ void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -411,20 +409,11 @@ void omap_sram_idle(void) core_next_state = omap3_pwrdm_read_next_pwrst(core_pwrdm); if (per_next_state PWRDM_POWER_ON) { omap2_gpio_prepare_for_idle(per_next_state); - if (per_next_state == PWRDM_POWER_OFF) { - if (core_next_state == PWRDM_POWER_ON) { - per_next_state = PWRDM_POWER_RET; - pwrdm_set_next_pwrst(per_pwrdm, per_next_state); - per_state_modified = 1; - } else - omap3_per_save_context(); - } + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); omap_uart_prepare_idle(2); } - if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) - omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* * Disable smartreflex before entering WFI. * Only needed if we are going to enter retention or off. @@ -554,8 +543,6 @@ void omap_sram_idle(void) } omap2_gpio_resume_after_idle(); omap_uart_resume_idle(2); - if (per_state_modified) - pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -564,7 +551,6 @@ void omap_sram_idle(void) omap3_disable_io_chain(); } - pwrdm_post_transition(); } @@ -1239,7 +1225,6 @@ static 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); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv6 6/9] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clocks and idle status bits of the domain according to following rules: 1) functional clock check * get FCLK register content * ignore all clocks defined in idle_def.fclk_ignore * if any active functional clocks remain, domain can't idle 2) idle status check * get IDLEST register content * inverse it (any non-idle blocks are now as 1) * mask against idle_def.idlest_mask * if any bits remain high, domain can't idle These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 32 arch/arm/mach-omap2/clockdomains.h| 106 + arch/arm/mach-omap2/powerdomain.c | 20 + arch/arm/plat-omap/include/plat/clockdomain.h | 17 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 176 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index a38a615..9ebff51 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -867,6 +867,38 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-clk_reg_num; i++) { + u32 idlest, fclk; + + fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_FCLKEN + 4 * i); + if (fclk ~clkdm-idle_def[i].fclk_ignore) + return 0; + + idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + CM_IDLEST + 4 * i); + if (~idlest clkdm-idle_def[i].idlest_mask) + return 0; + } + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index 8fc19ff..5e29de8 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -663,6 +663,12 @@ static struct clockdomain iva2_clkdm = { .wkdep_srcs = iva2_wkdeps, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430_ST_IVA2, + }, + }, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -686,6 +692,12 @@ static struct clockdomain sgx_clkdm = { .sleepdep_srcs = gfx_sgx_sleepdeps, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .clk_reg_num= 1, + .idle_def = { + [0] = { + .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT, + }, + }, }; /* @@ -717,6 +729,57 @@ static struct clockdomain core_l3_3xxx_clkdm = { .dep_bit= OMAP3430_EN_CORE_SHIFT, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .clk_reg_num= 3, + .idle_def = { + [0] = { + /* UARTs are controlled by idle loop so ignore */ + .fclk_ignore = OMAP3430_EN_UART2 | + OMAP3430_EN_UART1, + /* +* Reason for IDLEST ignores: +* - SDRC and OMAPCTRL controlled by HW +* - HSOTGUSB_IDLE bit is autoidled by HW +* - MAILBOX is controlled by HW +*/ + .idlest_mask = + OMAP3430ES2_ST_MMC3_MASK | + OMAP3430_ST_ICR_MASK | + OMAP3430_ST_AES2_MASK | + OMAP3430_ST_SHA12_MASK | + OMAP3430_ST_DES2_MASK | + OMAP3430_ST_MMC2_MASK
[PATCHv6 9/9] OMAP3: PM: Added support for suspending to INACTIVE state
From: Tero Kristo tero.kri...@nokia.com With the new support functions this is now possible. Suspending to INACTIVE is useful for testing purposes. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 11 ++- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index cdbedcf..41d6cc3 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -633,11 +633,12 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) if (pwrdm == NULL || IS_ERR(pwrdm)) return -EINVAL; - while (!(pwrdm-pwrsts (1 state))) { - if (state == PWRDM_POWER_OFF) - return ret; - state--; - } + if (state != PWRDM_POWER_INACTIVE) + while (!(pwrdm-pwrsts (1 state))) { + if (state == PWRDM_POWER_OFF) + return ret; + state--; + } cur_state = pwrdm_read_next_pwrst(pwrdm); if (cur_state == state) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv6 7/9] OMAP3: CPUidle: Added peripheral pwrdm checks into bm check
From: Tero Kristo tero.kri...@nokia.com Following checks are made (and their reasoning): - If CAM domain is active, prevent idle completely * CAM pwrdm does not have HW wakeup capability - If PER is likely to remain on, prevent PER off * Saves on unnecessary context save/restore - If CORE domain is active, prevent PER off-mode * PER off in this case would prevent wakeups from PER completely - Only allow CORE off, if all peripheral domains are off * CORE off will cause a chipwide reset Also, enabled CHECK_BM flag for C2, as this is needed for the camera case. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 104 ++--- 1 files changed, 97 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 86f580b..914022f 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -58,7 +58,8 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd; +static struct powerdomain *mpu_pd, *core_pd, *per_pd; +static struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd; /* * The latencies/thresholds for various C states have @@ -153,14 +154,96 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; - - if ((state-flags CPUIDLE_FLAG_CHECK_BM) omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); - new_state = dev-safe_state; + u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; + u32 iva2_state, sgx_state, dss_state, new_core_state; + struct omap3_processor_cx *cx; + int ret; + + if (state-flags CPUIDLE_FLAG_CHECK_BM) { + if (omap3_idle_bm_check()) { + BUG_ON(!dev-safe_state); + new_state = dev-safe_state; + goto select_state; + } + cx = cpuidle_get_statedata(state); + new_core_state = cx-core_state; + + /* Check if CORE is active, if yes, fallback to inactive */ + if (!pwrdm_can_idle(core_pd)) + new_core_state = PWRDM_POWER_INACTIVE; + + /* +* Prevent idle completely 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) { + new_state = dev-safe_state; + goto select_state; + } + + /* +* Check if PER can idle or not. If we are not likely +* to idle, deny PER off. This prevents unnecessary +* context save/restore. +*/ + saved_per_state = omap3_pwrdm_read_next_pwrst(per_pd); + if (pwrdm_can_idle(per_pd)) { + per_state = saved_per_state; + /* +* Prevent PER off if CORE is active as this +* would disable PER wakeups completely +*/ + if (per_state == PWRDM_POWER_OFF + new_core_state PWRDM_POWER_RET) + per_state = PWRDM_POWER_RET; + + } else if (saved_per_state == PWRDM_POWER_OFF) + per_state = PWRDM_POWER_RET; + else + per_state = saved_per_state; + + /* +* If we are attempting CORE off, check if any other +* powerdomains are at retention or higher. CORE off causes +* chipwide reset which would reset these domains also. +*/ + if (new_core_state == PWRDM_POWER_OFF) { + dss_state = pwrdm_read_pwrst(dss_pd); + iva2_state = pwrdm_read_pwrst(iva2_pd); + sgx_state = pwrdm_read_pwrst(sgx_pd); + usb_state = pwrdm_read_pwrst(usb_pd); + + if (cam_state PWRDM_POWER_OFF || + dss_state PWRDM_POWER_OFF || + iva2_state PWRDM_POWER_OFF || + per_state PWRDM_POWER_OFF || + sgx_state PWRDM_POWER_OFF || + usb_state PWRDM_POWER_OFF) + new_core_state = PWRDM_POWER_RET; + } + + /* Fallback to new target core state */ + while (cx-core_state new_core_state) { + state--; + cx = cpuidle_get_statedata(state
[PATCHv5] OMAP3: Serial: Improved sleep logic
From: Tero Kristo tero.kri...@nokia.com This patch contains following improvements: - Only RX interrupt will now kick the sleep prevent timer - TX fifo status is checked before disabling clocks, this will prevent on-going transmission to be cut - Smartidle is now enabled/disabled only while switching clocks, as having smartidle enabled while RX/TX prevents any interrupts from being received from UART module - Sleep prevent timer is changed to use timespec instead of a jiffy timer as jiffy timers are not valid within idle loop (tick scheduler is stopped) - Added RX ignore timer for ignoring the first character received during first millisecond of wakeup, this prevents garbage character to be receive in low sleep states Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/serial.c | 98 + 1 files changed, 69 insertions(+), 29 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 5f3035e..f49c465 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -29,6 +29,8 @@ #include plat/clock.h #include plat/control.h +#include asm/div64.h + #include prm.h #include pm.h #include prm-regbits-34xx.h @@ -42,13 +44,14 @@ * disabled via sysfs. This also causes that any deeper omap sleep states are * blocked. */ -#define DEFAULT_TIMEOUT 0 +#define DEFAULT_TIMEOUT (0LL * NSEC_PER_SEC) struct omap_uart_state { int num; int can_sleep; - struct timer_list timer; - u32 timeout; + struct timespec expire_time; + struct timespec garbage_time; + u64 timeout; void __iomem *wk_st; void __iomem *wk_en; @@ -243,6 +246,9 @@ static inline void omap_uart_save_context(struct omap_uart_state *uart) {} static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} #endif /* CONFIG_PM CONFIG_ARCH_OMAP3 */ +static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, + int enable); + static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) { if (uart-clocked) @@ -250,8 +256,13 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) clk_enable(uart-ick); clk_enable(uart-fck); + omap_uart_smart_idle_enable(uart, 0); uart-clocked = 1; omap_uart_restore_context(uart); + + /* Set up garbage timer to ignore RX during first 1ms */ + getrawmonotonic(uart-garbage_time); + timespec_add_ns(uart-garbage_time, NSEC_PER_MSEC); } #ifdef CONFIG_PM @@ -263,6 +274,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) omap_uart_save_context(uart); uart-clocked = 0; + omap_uart_smart_idle_enable(uart, 1); clk_disable(uart-ick); clk_disable(uart-fck); } @@ -320,12 +332,11 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) { omap_uart_enable_clocks(uart); - omap_uart_smart_idle_enable(uart, 0); uart-can_sleep = 0; - if (uart-timeout) - mod_timer(uart-timer, jiffies + uart-timeout); - else - del_timer(uart-timer); + if (uart-timeout) { + getrawmonotonic(uart-expire_time); + timespec_add_ns(uart-expire_time, uart-timeout); + } } static void omap_uart_allow_sleep(struct omap_uart_state *uart) @@ -338,25 +349,24 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart) if (!uart-clocked) return; - omap_uart_smart_idle_enable(uart, 1); uart-can_sleep = 1; - del_timer(uart-timer); -} - -static void omap_uart_idle_timer(unsigned long data) -{ - struct omap_uart_state *uart = (struct omap_uart_state *)data; - - omap_uart_allow_sleep(uart); } void omap_uart_prepare_idle(int num) { struct omap_uart_state *uart; + struct timespec t; list_for_each_entry(uart, uart_list, node) { + if (num == uart-num !uart-can_sleep uart-timeout) { + getrawmonotonic(t); + if (timespec_compare(t, uart-expire_time) 0) + uart-can_sleep = 1; + } if (num == uart-num uart-can_sleep) { - omap_uart_disable_clocks(uart); + if (serial_read_reg(uart-p, UART_LSR) + UART_LSR_TEMT) + omap_uart_disable_clocks(uart); return; } } @@ -381,6 +391,7 @@ void omap_uart_resume_idle(int num) /* Check for normal UART wakeup */ if (__raw_readl(uart-wk_st) uart-wk_mask) omap_uart_block_sleep(uart); + return; } } @@ -399,11 +410,18 @@ int omap_uart_can_sleep(void
[PATCHv6] OMAP3: Serial: Improved sleep logic
From: Tero Kristo tero.kri...@nokia.com This patch contains following improvements: - Only RX interrupt will now kick the sleep prevent timer - TX fifo status is checked before disabling clocks, this will prevent on-going transmission to be cut - Smartidle is now enabled/disabled only while switching clocks, as having smartidle enabled while RX/TX prevents any wakeups from being received from UART module - Added workqueue for wakeup checks, as jiffy timer access within the idle loop results into skewed timers as jiffy timers are stopped - Added garbage_timer for ignoring the first character received during the first tick after clock enable, this prevents garbage characters to be received in low sleep states - omap_uart_enable_irqs() changed to use enable_irq / disable_irq instead of request / free. Using request/free changes the behavior after first suspend due to reversed interrupt handler ordering Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/serial.c | 67 +++--- 1 files changed, 56 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 5f3035e..06d18f5 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -23,6 +23,7 @@ #include linux/serial_reg.h #include linux/clk.h #include linux/io.h +#include linux/workqueue.h #include plat/common.h #include plat/board.h @@ -48,7 +49,10 @@ struct omap_uart_state { int num; int can_sleep; struct timer_list timer; + struct timer_list garbage_timer; + struct work_struct wakeup_work; u32 timeout; + u8 garbage_ignore; void __iomem *wk_st; void __iomem *wk_en; @@ -243,6 +247,11 @@ static inline void omap_uart_save_context(struct omap_uart_state *uart) {} static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} #endif /* CONFIG_PM CONFIG_ARCH_OMAP3 */ +#ifdef CONFIG_PM +static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, + int enable); +#endif + static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) { if (uart-clocked) @@ -252,6 +261,15 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) clk_enable(uart-fck); uart-clocked = 1; omap_uart_restore_context(uart); +#ifdef CONFIG_PM + omap_uart_smart_idle_enable(uart, 0); +#endif + + /* Set up garbage timer to ignore RX during first jiffy */ + if (uart-timeout) { + mod_timer(uart-garbage_timer, jiffies + 1); + uart-garbage_ignore = 1; + } } #ifdef CONFIG_PM @@ -263,6 +281,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) omap_uart_save_context(uart); uart-clocked = 0; + omap_uart_smart_idle_enable(uart, 1); clk_disable(uart-ick); clk_disable(uart-fck); } @@ -320,7 +339,6 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) { omap_uart_enable_clocks(uart); - omap_uart_smart_idle_enable(uart, 0); uart-can_sleep = 0; if (uart-timeout) mod_timer(uart-timer, jiffies + uart-timeout); @@ -338,7 +356,6 @@ static void omap_uart_allow_sleep(struct omap_uart_state *uart) if (!uart-clocked) return; - omap_uart_smart_idle_enable(uart, 1); uart-can_sleep = 1; del_timer(uart-timer); } @@ -350,13 +367,30 @@ static void omap_uart_idle_timer(unsigned long data) omap_uart_allow_sleep(uart); } +static void omap_uart_garbage_timer(unsigned long data) +{ + struct omap_uart_state *uart = (struct omap_uart_state *)data; + + uart-garbage_ignore = 0; +} + +static void omap_uart_wakeup_work(struct work_struct *work) +{ + struct omap_uart_state *uart = + container_of(work, struct omap_uart_state, wakeup_work); + + omap_uart_block_sleep(uart); +} + void omap_uart_prepare_idle(int num) { struct omap_uart_state *uart; list_for_each_entry(uart, uart_list, node) { if (num == uart-num uart-can_sleep) { - omap_uart_disable_clocks(uart); + if (serial_read_reg(uart-p, UART_LSR) + UART_LSR_TEMT) + omap_uart_disable_clocks(uart); return; } } @@ -375,12 +409,12 @@ void omap_uart_resume_idle(int num) u16 p = omap_ctrl_readw(uart-padconf); if (p OMAP3_PADCONF_WAKEUPEVENT0) - omap_uart_block_sleep(uart); + schedule_work(uart-wakeup_work); } /* Check for normal UART wakeup */ if (__raw_readl(uart-wk_st
[PATCHv2 0/11] Misc fixes [for PM branch]
From: Tero Kristo tero.kri...@nokia.com This set is now missing following patches compared to the previous set: - IVA2 suspend fix - Dynamic check for core target state - Block core off when DSS active - Next state check for IVA2, USB and PER - USBHOST powerdomain force to sleep after warm reset Also removed one of the patches Kevin already applied. I am still trying to figure out what to do with the remaining patches, but I decided I would send this partial set which I have modified according to comments already. -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/11] OMAP3: Disable Smartreflex before pwrdm enters RET
From: Tero Kristo tero.kri...@nokia.com Smartreflex for the corresponding powerdomain (MPU/CORE) must be disabled before the domain enters retention, otherwise the device may hang. This is caused by overlapping smartreflex / auto retention command on the voltage channel resulting in incorrect voltage. This fix has been confirmed from TI. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 22 +- 1 files changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 8353764..6782792 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -403,11 +403,17 @@ void omap_sram_idle(void) if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* CORE */ - if (core_next_state PWRDM_POWER_ON) { - /* Disable smartreflex before entering WFI */ + /* +* Disable smartreflex before entering WFI. +* Only needed if we are going to enter retention or off. +*/ + if (mpu_next_state = PWRDM_POWER_RET) disable_smartreflex(SR1); + if (core_next_state = PWRDM_POWER_RET) disable_smartreflex(SR2); + + /* CORE */ + if (core_next_state PWRDM_POWER_ON) { omap_uart_prepare_idle(0); omap_uart_prepare_idle(1); if (core_next_state == PWRDM_POWER_OFF) { @@ -480,10 +486,16 @@ void omap_sram_idle(void) prm_clear_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); - /* Enable smartreflex after WFI */ + } + + /* +* Enable smartreflex after WFI. Only needed if we entered +* retention or off +*/ + if (mpu_next_state = PWRDM_POWER_RET) enable_smartreflex(SR1); + if (core_next_state = PWRDM_POWER_RET) enable_smartreflex(SR2); - } /* PER */ if (per_next_state PWRDM_POWER_ON) { -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/11] OMAP3: PM: Ack pending interrupts before entering suspend
From: Tero Kristo tero.kri...@nokia.com Suspending drivers may still generate interrupts just before their suspend is completed. Any pending interrupts here will prevent sleep. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/irq.c |6 ++ arch/arm/mach-omap2/pm34xx.c |2 +- arch/arm/plat-omap/include/mach/irqs.h |1 + 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index aceedd8..ee8c68a 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -266,4 +266,10 @@ void omap3_intc_restore_context(void) } /* MIRs are saved and restore with other PRCM registers */ } + +void omap3_intc_suspend(void) +{ + /* A pending interrupt would prevent OMAP from entering suspend */ + omap_ack_irq(0); +} #endif /* CONFIG_ARCH_OMAP3 */ diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 6782792..53544d3 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -640,7 +640,7 @@ static int omap3_pm_suspend(void) } omap_uart_prepare_suspend(); - + omap3_intc_suspend(); regset_save_on_suspend = 1; omap_sram_idle(); regset_save_on_suspend = 0; diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h index 2473910..ff1faa8 100644 --- a/arch/arm/plat-omap/include/mach/irqs.h +++ b/arch/arm/plat-omap/include/mach/irqs.h @@ -485,6 +485,7 @@ extern void omap_init_irq(void); extern int omap_irq_pending(void); void omap3_intc_save_context(void); void omap3_intc_restore_context(void); +void omap3_intc_suspend(void); #endif #include mach/hardware.h -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 03/11] OMAP2/3: DMTIMER: Clear pending interrupts when stopping a timer
From: Tero Kristo tero.kri...@nokia.com OMAP GP timers keep running for a few cycles after they are stopped, which can cause the timer to expire and generate an interrupt. The pending interrupt will prevent e.g. OMAP from entering suspend, thus we ack it manually. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/plat-omap/dmtimer.c | 10 ++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 830b072..09a623d 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -551,6 +551,16 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer) if (l OMAP_TIMER_CTRL_ST) { l = ~0x1; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); + /* Readback to make sure write has completed */ + omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); +/* + * Wait for functional clock period x 3.5 to make sure that + * timer is stopped + */ + udelay(350 / clk_get_rate(timer-fclk) + 1); + /* Ack possibly pending interrupt */ + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, + OMAP_TIMER_INT_OVERFLOW); } } EXPORT_SYMBOL_GPL(omap_dm_timer_stop); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/11] OMAP3: PM: Disable interrupt controller AUTOIDLE before WFI
From: Tero Kristo tero.kri...@nokia.com OMAP interrupt controller goes to unknown state when there is right combination of l3,l4 sleep/wake-up transitions, l4 autoidle in interrupt controller and some interrupt. When this happens, interrupts are not delivered to ARM anymore and ARM will remain in WFI (wait for interrupt) until interrupt controller is forced to wake-up (i.e. lauterbach). Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/irq.c | 12 arch/arm/mach-omap2/pm34xx.c |2 ++ arch/arm/plat-omap/include/mach/irqs.h |2 ++ 3 files changed, 16 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index ee8c68a..9241b87 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -272,4 +272,16 @@ void omap3_intc_suspend(void) /* A pending interrupt would prevent OMAP from entering suspend */ omap_ack_irq(0); } + +void omap3_intc_prepare_idle(void) +{ + /* Disable autoidle as it can stall interrupt controller */ + intc_bank_write_reg(0, irq_banks[0], INTC_SYSCONFIG); +} + +void omap3_intc_resume_idle(void) +{ + /* Re-enable autoidle */ + intc_bank_write_reg(1, irq_banks[0], INTC_SYSCONFIG); +} #endif /* CONFIG_ARCH_OMAP3 */ diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 492458e..fec9c38 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -431,6 +431,7 @@ void omap_sram_idle(void) prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_enable_io_chain(); } + omap3_intc_prepare_idle(); /* * On EMU/HS devices ROM code restores a SRDC value @@ -487,6 +488,7 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } + omap3_intc_resume_idle(); /* * Enable smartreflex after WFI. Only needed if we entered diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h index ff1faa8..b736c5d 100644 --- a/arch/arm/plat-omap/include/mach/irqs.h +++ b/arch/arm/plat-omap/include/mach/irqs.h @@ -486,6 +486,8 @@ extern int omap_irq_pending(void); void omap3_intc_save_context(void); void omap3_intc_restore_context(void); void omap3_intc_suspend(void); +void omap3_intc_prepare_idle(void); +void omap3_intc_resume_idle(void); #endif #include mach/hardware.h -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 07/11] OMAP3: Fixed ARM aux ctrl register save/restore
From: Tero Kristo tero.kri...@nokia.com Current value is stored on SDRAM and it is written back during wakeup. Previously a static value of 0x72 was written there. Signed-off-by: Tero Kristo tero.kri...@nokia.com Signed-off-by: Jouni Hogander jouni.hogan...@nokia.com --- arch/arm/mach-omap2/control.c |1 + arch/arm/mach-omap2/sleep34xx.S | 23 --- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 296f2c2..730fc53 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -94,6 +94,7 @@ void *omap3_secure_ram_storage; * during the restore path. */ u32 omap3_arm_context[128]; +u32 omap3_aux_ctrl[2] = { 0x1, 0x0 }; struct omap3_control_regs { u32 sysconfig; diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index f4f5ebe..0b03bf9 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -26,6 +26,7 @@ */ #include linux/linkage.h #include asm/assembler.h +#include asm/memory.h #include mach/io.h #include mach/control.h @@ -278,7 +279,11 @@ restore: mov r1, #0 @ set task id for ROM code in r1 mov r2, #4 @ set some flags in r2, r6 mov r6, #0xff - adr r3, write_aux_control_params@ r3 points to parameters + ldr r3, write_aux_control_params@ r3 points to parameters + ldr r4, phys_offset + addsr3, r3, r4 + ldr r4, page_offset + subsr3, r3, r4 mcr p15, 0, r0, c7, c10, 4 @ data write barrier mcr p15, 0, r0, c7, c10, 5 @ data memory barrier .word 0xE1600071 @ call SMI monitor (smi #1) @@ -287,13 +292,18 @@ restore: l2_inv_api_params: .word 0x1, 0x00 write_aux_control_params: - .word 0x1, 0x72 + .word omap3_aux_ctrl l2_inv_gp: /* Execute smi to invalidate L2 cache */ mov r12, #0x1 @ set up to invalide L2 smi:.word 0xE1600070 @ Call SMI monitor (smieq) /* Write to Aux control register to set some bits */ - mov r0, #0x72 + ldr r1, write_aux_control_params + ldr r0, phys_offset + addsr1, r1, r0 + ldr r0, page_offset + subsr1, r1, r0 + ldr r0, [r1, #4] mov r12, #0x3 .word 0xE1600070@ Call SMI monitor (smieq) logic_l1_restore: @@ -420,6 +430,9 @@ usettbr0: save_context_wfi: /*b save_context_wfi*/ @ enable to debug save code mov r8, r0 /* Store SDRAM address in r8 */ + mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary Control Register + ldr r5, write_aux_control_params + str r4, [r5, #4] /* Check what that target sleep state is:stored in r1*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost */ @@ -605,6 +618,10 @@ wait_dll_lock: bne wait_dll_lock bx lr +phys_offset: + .word PHYS_OFFSET +page_offset: + .word PAGE_OFFSET cm_idlest1_core: .word CM_IDLEST1_CORE_V sdrc_dlla_status: -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/11] OMAP3: PM: Disabled I2C4 repeated start operation mode
From: Tero Kristo tero.kri...@nokia.com Repeated start forces I2C4 pads low during idle, which increases power consumption through external pull-ups. On the other hand, this change increases I2C4 command latencies a bit. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index fec9c38..154cd31 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -1219,7 +1219,7 @@ static void __init configure_vc(void) prm_write_mod_reg(OMAP3430_CMD1 | OMAP3430_RAV1, OMAP3430_GR_MOD, OMAP3_PRM_VC_CH_CONF_OFFSET); - prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN, + prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN, OMAP3430_GR_MOD, OMAP3_PRM_VC_I2C_CFG_OFFSET); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 05/11] OMAP3: PM: Enable system control module autoidle
From: Tero Kristo tero.kri...@nokia.com This saves some power. Signed-off-by: Mika Westerberg ext-mika.1.westerb...@nokia.com --- arch/arm/mach-omap2/pm34xx.c |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 53544d3..492458e 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -900,6 +900,8 @@ static void __init prcm_setup_regs(void) CM_AUTOIDLE); } + omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG); + /* * Set all plls to autoidle. This is needed until autoidle is * enabled by clockfw -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/11] OMAP3: PM: Added support for L2 aux ctrl register save and restore
From: Tero Kristo tero.kri...@nokia.com This patch adds a save and restore mechanism for ARM L2 auxiliary control register. This feature is enabled via Kconfig option OMAP3_L2_AUX_SECURE_SAVE_RESTORE and the service ID for PPA can be provided via option OMAP3_L2_AUX_SECURE_SERVICE_SET_ID. If bootloader does not modify L2 aux register, using this save and restore logic for it is not needed. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/control.c |1 + arch/arm/mach-omap2/sleep34xx.S | 31 +++ arch/arm/plat-omap/Kconfig | 17 + 3 files changed, 49 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 730fc53..82d8f1a 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -95,6 +95,7 @@ void *omap3_secure_ram_storage; */ u32 omap3_arm_context[128]; u32 omap3_aux_ctrl[2] = { 0x1, 0x0 }; +u32 omap3_l2_aux_ctrl[2] = { 0x1, 0x0 }; struct omap3_control_regs { u32 sysconfig; diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index 0b03bf9..e291d6d 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -288,11 +288,30 @@ restore: mcr p15, 0, r0, c7, c10, 5 @ data memory barrier .word 0xE1600071 @ call SMI monitor (smi #1) +#ifdef CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE + /* Restore L2 aux control register */ + @ set service ID for PPA + mov r0, #CONFIG_OMAP3_L2_AUX_SECURE_SERVICE_SET_ID + mov r12, r0 @ copy service ID in r12 + mov r1, #0 @ set task ID for ROM code in r1 + mov r2, #4 @ set some flags in r2, r6 + mov r6, #0xff + ldr r3, write_l2_aux_control_params @ r3 points to parameters + ldr r4, phys_offset + addsr3, r3, r4 + ldr r4, page_offset + subsr3, r3, r4 + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 @ data memory barrier + .word 0xE1600071 @ call SMI monitor (smi #1) +#endif b logic_l1_restore l2_inv_api_params: .word 0x1, 0x00 write_aux_control_params: .word omap3_aux_ctrl +write_l2_aux_control_params: + .word omap3_l2_aux_ctrl l2_inv_gp: /* Execute smi to invalidate L2 cache */ mov r12, #0x1 @ set up to invalide L2 @@ -306,6 +325,15 @@ smi:.word 0xE1600070 @ Call SMI monitor (smieq) ldr r0, [r1, #4] mov r12, #0x3 .word 0xE1600070@ Call SMI monitor (smieq) + /* Restore L2 AUX control register */ + ldr r1, write_l2_aux_control_params + ldr r0, phys_offset + addsr1, r1, r0 + ldr r0, page_offset + subsr1, r1, r0 + ldr r0, [r1, #4] + mov r12, #0x2 + .word 0xE1600070@ Call SMI monitor (smieq) logic_l1_restore: mov r1, #0 /* Invalidate all instruction caches to PoU @@ -433,6 +461,9 @@ save_context_wfi: mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary Control Register ldr r5, write_aux_control_params str r4, [r5, #4] + mrc p15, 1, r4, c9, c0, 2 @ Read L2 AUX ctrl register + ldr r5, write_l2_aux_control_params + str r4, [r5, #4] /* Check what that target sleep state is:stored in r1*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost */ diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 2143db5..3ff1a5f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -185,6 +185,23 @@ config OMAP3_DEBOBS help Use ETK pads for debug observability +config OMAP3_L2_AUX_SECURE_SAVE_RESTORE + bool OMAP3 HS/EMU save and restore for L2 AUX control register + depends on ARCH_OMAP3 PM + default n + help + Without this option, L2 Auxiliary control register contents are + lost during off-mode entry on HS/EMU devices. This feature + requires support from PPA / boot-loader in HS/EMU devices, which + currently does not exist by default. + +config OMAP3_L2_AUX_SECURE_SERVICE_SET_ID + int Service ID for the support routine to set L2 AUX control + depends on OMAP3_L2_AUX_SECURE_SAVE_RESTORE + default 43 + help + PPA routine service ID for setting L2 auxiliary control register. + config OMAP_32K_TIMER_HZ int Kernel internal timer frequency for 32KHz timer range 32 1024 -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/11] OMAP3: PM: Write voltage and clock setup times dynamically in idle loop
From: Tero Kristo tero.kri...@nokia.com It is suggested by TI (SWPA152 February 2009) to write clksetup, voltsetup_time1, voltsetup_time2, voltsetup2 dynamically in idle loop. This allows us to optimize the voltage + clock setup times according to the used power save mode. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm.h | 10 - arch/arm/mach-omap2/pm34xx.c | 86 -- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index f8d11a2..b384eb1 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -24,12 +24,18 @@ extern int omap3_can_sleep(void); extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); extern int omap3_idle_init(void); -struct prm_setup_vc { +struct prm_setup_times_vc { u16 clksetup; u16 voltsetup_time1; u16 voltsetup_time2; - u16 voltoffset; u16 voltsetup2; + u16 voltsetup1; +}; + +struct prm_setup_vc { + struct prm_setup_times_vc *setup_times; + struct prm_setup_times_vc *setup_times_off; + u16 voltoffset; /* PRM_VC_CMD_VAL_0 specific bits */ u16 vdd0_on; u16 vdd0_onlp; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 154cd31..5eb7321 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -82,12 +82,17 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; static struct powerdomain *cam_pwrdm; -static struct prm_setup_vc prm_setup = { +static struct prm_setup_times_vc prm_setup_times_default = { .clksetup = 0xff, .voltsetup_time1 = 0xfff, .voltsetup_time2 = 0xfff, - .voltoffset = 0xff, .voltsetup2 = 0xff, +}; + +static struct prm_setup_vc prm_setup_default = { + .setup_times = prm_setup_times_default, + .setup_times_off = NULL, + .voltoffset = 0xff, .vdd0_on = 0x30,/* 1.2v */ .vdd0_onlp = 0x20, /* 1.0v */ .vdd0_ret = 0x1e, /* 0.975v */ @@ -98,6 +103,8 @@ static struct prm_setup_vc prm_setup = { .vdd1_off = 0x00, /* 0.6v */ }; +static struct prm_setup_vc *prm_setup = prm_setup_default; + static inline void omap3_per_save_context(void) { omap3_gpio_save_context(); @@ -338,6 +345,16 @@ static void restore_table_entry(void) restore_control_register(control_reg_value); } +static void prm_program_setup_times(struct prm_setup_times_vc *times) +{ + prm_write_mod_reg(times-voltsetup1, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTSETUP1_OFFSET); + prm_write_mod_reg(times-voltsetup2, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTSETUP2_OFFSET); + prm_write_mod_reg(times-clksetup, OMAP3430_GR_MOD, + OMAP3_PRM_CLKSETUP_OFFSET); +} + void omap_sram_idle(void) { /* Variable to tell what needs to be saved and restored @@ -422,6 +439,9 @@ void omap_sram_idle(void) OMAP3_PRM_VOLTCTRL_OFFSET); omap3_core_save_context(); omap3_prcm_save_context(); + if (prm_setup-setup_times_off != NULL) + prm_program_setup_times(prm_setup- + setup_times_off); } else if (core_next_state == PWRDM_POWER_RET) { prm_set_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, @@ -479,11 +499,13 @@ void omap_sram_idle(void) } omap_uart_resume_idle(0); omap_uart_resume_idle(1); - if (core_next_state == PWRDM_POWER_OFF) + if (core_next_state == PWRDM_POWER_OFF) { prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); - else if (core_next_state == PWRDM_POWER_RET) + if (prm_setup-setup_times_off != NULL) + prm_program_setup_times(prm_setup-setup_times); + } else if (core_next_state == PWRDM_POWER_RET) prm_clear_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); @@ -1043,21 +1065,19 @@ int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) return -EINVAL; } +static void omap3_init_prm_setup_times(struct prm_setup_times_vc *conf) +{ + if (conf == NULL) + return; + + conf-voltsetup1 = + (conf-voltsetup_time2 OMAP3430_SETUP_TIME2_SHIFT) | + (conf-voltsetup_time1 OMAP3430_SETUP_TIME1_SHIFT
[PATCH 01/11] OMAP3: PM: Fixed padconf save done check
From: Carlos Chinea carlos.chi...@nokia.com Previously the operator precedence dictated that the delay loop was exited immediately, potentially causing off-mode to be entered too soon. Signed-off-by: Carlos Chinea carlos.chi...@nokia.com Signed-off-by: Jouni Hogander jouni.hogan...@nokia.com --- arch/arm/mach-omap2/pm34xx.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 01260ec..8353764 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -146,8 +146,8 @@ static void omap3_core_save_context(void) control_padconf_off |= START_PADCONF_SAVE; omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF); /* wait for the save to complete */ - while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) -PADCONF_SAVE_DONE) + while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) +PADCONF_SAVE_DONE)) ; /* Save the Interrupt controller context */ omap3_intc_save_context(); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] OMAP3: CPUidle: Fixed timer resolution
From: Tero Kristo tero.kri...@nokia.com Previously used u32 as temporary data storage that wraps around at 4.294s. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index a0d9f56..0ac3b63 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -137,7 +137,7 @@ return_sleep_time: local_irq_enable(); local_fiq_enable(); - return (u32)timespec_to_ns(ts_idle)/1000; + return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; } /** -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] OMAP3: PM: Check BM for C2 state
From: De-Schrijver Peter peter.de-schrij...@nokia.com C2 can't be entered while we have bus activity. Signed-off-by: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c |7 --- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index c44a942..a0d9f56 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -38,7 +38,7 @@ #define OMAP3_MAX_STATES 7 #define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */ -#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */ +#define OMAP3_STATE_C2 1 /* C2 - MPU inactive + Core inactive */ #define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */ #define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */ #define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */ @@ -169,7 +169,7 @@ DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); * * Below is the desciption of each C state. * C1 . MPU WFI + Core active - * C2 . MPU WFI + Core inactive + * C2 . MPU inactive + Core inactive * C3 . MPU CSWR + Core inactive * C4 . MPU OFF + Core inactive * C5 . MPU CSWR + Core CSWR @@ -196,7 +196,8 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C2].threshold = 30; omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; + omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_CHECK_BM; /* C3 . MPU CSWR + Core inactive */ omap3_power_states[OMAP3_STATE_C3].valid = 1; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2] OMAP3: Cpuidle fixes
From: Tero Kristo tero.kri...@nokia.com Following patches apply on top of PM branch. They implement a couple of small fixes for cpuidle. Timer resolution patch probably does not change anything until kernel cpuidle is fixed to support longer timers (there are some pending patches for this.) -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/4] RX51: Fix SDRAM RFR timings calculation
From: Kalle Jokiniemi kalle.jokini...@digia.com sdrc_ps_to_ticks introduced some unnecessary rounding error to SDRC_RFR value calculation. Fixed by adding 10^3 more accuracy before division and skipping the sdrc_ps_to_ticks call. Problem-reported-by: Jukka S. Laitinen jukka.s.laiti...@nokia.com Signed-off-by: Kalle Jokiniemi kalle.jokini...@digia.com --- arch/arm/mach-omap2/board-rx51-sdram.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c index 237b898..f3b9917 100644 --- a/arch/arm/mach-omap2/board-rx51-sdram.c +++ b/arch/arm/mach-omap2/board-rx51-sdram.c @@ -166,7 +166,7 @@ static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit, static int sdrc_timings(int id, long rate) { - u32 ticks_per_us; + u32 ticks_per_ms; u32 rfr, l; u32 actim_ctrla = 0, actim_ctrlb = 0; u32 rfr_ctrl; @@ -192,8 +192,8 @@ static int sdrc_timings(int id, long rate) SDRC_SET_ONE(actim_ctrlb, 12, 14, tCKE, l3_rate); SDRC_SET_ONE(actim_ctrlb, 16, 17, tWTR, l3_rate); - ticks_per_us = sdrc_ps_to_ticks(100, l3_rate); - rfr = rx51_timings[0].tREF * ticks_per_us / 1000; + ticks_per_ms = l3_rate; + rfr = rx51_timings[0].tREF * ticks_per_ms / 100; if (rfr 65535 + 50) rfr = 65535; else -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/4] RX51: Add SDRAM configs for different OPPs
From: Tero Kristo tero.kri...@nokia.com This modification is needed by DVFS. Signed-off-by: Tero Kristo tero.kri...@nokia.com Signed-off-by: Jouni Hogander jouni.hogan...@nokia.com --- arch/arm/mach-omap2/board-rx51-sdram.c | 84 ++-- 1 files changed, 47 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c index 6f1f33c..78cd5ed 100644 --- a/arch/arm/mach-omap2/board-rx51-sdram.c +++ b/arch/arm/mach-omap2/board-rx51-sdram.c @@ -44,7 +44,7 @@ struct sdram_info { }; -struct omap_sdrc_params rx51_sdrc_params[2]; +struct omap_sdrc_params rx51_sdrc_params[4]; static const struct sdram_timings rx51_timings[] = { { @@ -118,30 +118,28 @@ static unsigned long get_l3_rate(void) return get_core_rate() / (l 0x03); } - - -static unsigned long sdrc_get_fclk_period(void) +static unsigned long sdrc_get_fclk_period(long rate) { /* In picoseconds */ - return 10 / get_l3_rate(); + return 10 / rate; } -static unsigned int sdrc_ps_to_ticks(unsigned int time_ps) +static unsigned int sdrc_ps_to_ticks(unsigned int time_ps, long rate) { unsigned long tick_ps; /* Calculate in picosecs to yield more exact results */ - tick_ps = sdrc_get_fclk_period(); + tick_ps = sdrc_get_fclk_period(rate); return (time_ps + tick_ps - 1) / tick_ps; } #undef DEBUG #ifdef DEBUG static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, - int time, const char *name) + int time, long rate, const char *name) #else static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, - int time) + int time, long rate) #endif { int ticks, mask, nr_bits; @@ -149,7 +147,7 @@ static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, if (time == 0) ticks = 0; else - ticks = sdrc_ps_to_ticks(time); + ticks = sdrc_ps_to_ticks(time, rate); nr_bits = end_bit - st_bit + 1; if (ticks = 1 nr_bits) return -1; @@ -158,42 +156,46 @@ static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, *regval |= ticks st_bit; #ifdef DEBUG printk(SDRC %s: %i ticks %i ns\n, name, ticks, - (unsigned int)sdrc_get_fclk_period() * ticks / 1000); + (unsigned int)sdrc_get_fclk_period(rate) * ticks / + 1000); #endif return 0; } #ifdef DEBUG -#define SDRC_SET_ONE(reg, st, end, field) \ - if (set_sdrc_timing_regval((reg), (st), (end), rx51_timings-field, #field) 0) \ - err = -1 +#define SDRC_SET_ONE(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval((reg), (st), (end), \ + rx51_timings-field, (rate), #field) 0) \ + err = -1; #else -#define SDRC_SET_ONE(reg, st, end, field) \ - if (set_sdrc_timing_regval((reg), (st), (end), rx51_timings-field) 0) \ - err = -1 +#define SDRC_SET_ONE(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval((reg), (st), (end), \ + rx51_timings-field, (rate)) 0) \ + err = -1; #endif -struct omap_sdrc_params *rx51_get_sdram_timings(void) +static int sdrc_timings(int id, long rate) { u32 ticks_per_ms; u32 rfr, l; - u32 actim_ctrla, actim_ctrlb; + u32 actim_ctrla = 0, actim_ctrlb = 0; u32 rfr_ctrl; int err = 0; + long l3_rate = rate / 1000; - SDRC_SET_ONE(actim_ctrla, 0, 4, tDAL); - SDRC_SET_ONE(actim_ctrla, 6, 8, tDPL); - SDRC_SET_ONE(actim_ctrla, 9, 11, tRRD); - SDRC_SET_ONE(actim_ctrla, 12, 14, tRCD); - SDRC_SET_ONE(actim_ctrla, 15, 17, tRP); - SDRC_SET_ONE(actim_ctrla, 18, 21, tRAS); - SDRC_SET_ONE(actim_ctrla, 22, 26, tRC); - SDRC_SET_ONE(actim_ctrla, 27, 31, tRFC); + SDRC_SET_ONE(actim_ctrla, 0, 4, tDAL, l3_rate); + SDRC_SET_ONE(actim_ctrla, 6, 8, tDPL, l3_rate); + SDRC_SET_ONE(actim_ctrla, 9, 11, tRRD, l3_rate); + SDRC_SET_ONE(actim_ctrla, 12, 14, tRCD, l3_rate); + SDRC_SET_ONE(actim_ctrla, 15, 17, tRP, l3_rate); + SDRC_SET_ONE(actim_ctrla, 18, 21, tRAS, l3_rate); + SDRC_SET_ONE(actim_ctrla, 22, 26, tRC, l3_rate); + SDRC_SET_ONE(actim_ctrla, 27, 31, tRFC, l3_rate); - SDRC_SET_ONE(actim_ctrlb, 0, 7, tXSR); + SDRC_SET_ONE(actim_ctrlb, 0, 7, tXSR, l3_rate); - ticks_per_ms = sdrc_ps_to_ticks(10); + ticks_per_ms = sdrc_ps_to_ticks(10, l3_rate); rfr = rx51_timings[0].tREF * ticks_per_ms / (1 rx51_info.row_lines); if (rfr 65535 + 50) rfr = 65535; @@ -203,16 +205,24 @@ struct omap_sdrc_params
[PATCH 0/4] RX51: SDRAM settings changes
From: Tero Kristo tero.kri...@nokia.com Following patch set fixes a few issues with current RX51 board SDRAM settings. Applies on top of PM branch. -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/4] RX51: SDRC: change timing values to follow generic memory requirements
From: Onkalo Samu.P samu.p.onk...@nokia.com Current memory parameters are slightly off-spec. Also, a couple of unused functions removed from code. Signed-off-by: Samu Onkalo samu.p.onk...@nokia.com --- arch/arm/mach-omap2/board-rx51-sdram.c | 130 ++-- 1 files changed, 91 insertions(+), 39 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c index b5d1c55..237b898 100644 --- a/arch/arm/mach-omap2/board-rx51-sdram.c +++ b/arch/arm/mach-omap2/board-rx51-sdram.c @@ -1,5 +1,5 @@ /* - * SDRC register values for the Samsung K4X1G323PC + * SDRC register values for RX51 * * Copyright (C) 2008 Nokia Corporation * @@ -23,7 +23,7 @@ #include mach/sdrc.h -/* In picoseconds, except for tREF */ +/* In picoseconds, except for tREF (ns), tXP, tCKE, tWTR (clks) */ struct sdram_timings { u32 casl; u32 tDAL; @@ -36,7 +36,11 @@ struct sdram_timings { u32 tRFC; u32 tXSR; - u32 tREF; /* in ms */ + u32 tREF; /* in ns */ + + u32 tXP; + u32 tCKE; + u32 tWTR; }; struct sdram_info { @@ -49,22 +53,22 @@ struct omap_sdrc_params rx51_sdrc_params[4]; static const struct sdram_timings rx51_timings[] = { { .casl = 3, - .tDAL = 15000 + 18000, + .tDAL = 33000, .tDPL = 15000, .tRRD = 12000, - .tRCD = 18000, + .tRCD = 22500, .tRP = 18000, .tRAS = 42000, .tRC = 66000, - .tRFC = 97500, - .tXSR = 12, + .tRFC = 138000, + .tXSR = 20, - .tREF = 64, - }, -}; + .tREF = 7800, -static const struct sdram_info rx51_info = { - .row_lines = 13, + .tXP = 2, + .tCKE = 2, + .tWTR = 2 + }, }; static unsigned long sdrc_get_fclk_period(long rate) @@ -85,18 +89,14 @@ static unsigned int sdrc_ps_to_ticks(unsigned int time_ps, long rate) #undef DEBUG #ifdef DEBUG static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, - int time, long rate, const char *name) + int ticks, long rate, const char *name) #else static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, - int time, long rate) + int ticks) #endif { - int ticks, mask, nr_bits; + int mask, nr_bits; - if (time == 0) - ticks = 0; - else - ticks = sdrc_ps_to_ticks(time, rate); nr_bits = end_bit - st_bit + 1; if (ticks = 1 nr_bits) return -1; @@ -104,7 +104,7 @@ static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, *regval = ~(mask st_bit); *regval |= ticks st_bit; #ifdef DEBUG - printk(SDRC %s: %i ticks %i ns\n, name, ticks, + printk(KERN_INFO SDRC %s: %i ticks %i ns\n, name, ticks, (unsigned int)sdrc_get_fclk_period(rate) * ticks / 1000); #endif @@ -113,46 +113,98 @@ static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, } #ifdef DEBUG -#define SDRC_SET_ONE(reg, st, end, field, rate) \ - if (set_sdrc_timing_regval((reg), (st), (end), \ +#define SDRC_SET_ONE(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval((reg), (st), (end),\ rx51_timings-field, (rate), #field) 0) \ err = -1; #else -#define SDRC_SET_ONE(reg, st, end, field, rate) \ - if (set_sdrc_timing_regval((reg), (st), (end), \ - rx51_timings-field, (rate)) 0) \ +#define SDRC_SET_ONE(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval((reg), (st), (end), \ + rx51_timings-field, (rate)) 0) \ + err = -1; +#endif + +#ifdef DEBUG +static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit, + int time, long rate, const char *name) +#else +static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit, + int time, long rate) +#endif +{ + int ticks, ret; + ret = 0; + + if (time == 0) + ticks = 0; + else + ticks = sdrc_ps_to_ticks(time, rate); + +#ifdef DEBUG + ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks, +rate, name); +#else + ret = set_sdrc_timing_regval(regval, st_bit, end_bit, ticks); +#endif + + return ret; +} + +#ifdef DEBUG +#define SDRC_SET_ONE_PS(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval_ps((reg), (st),
[PATCH 2/4] RX51: SDRAM: Cleanup the init code
From: Tero Kristo tero.kri...@nokia.com Removed a few unused functions + macro definitions + variables from the code. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/board-rx51-sdram.c | 51 1 files changed, 0 insertions(+), 51 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c index 78cd5ed..b5d1c55 100644 --- a/arch/arm/mach-omap2/board-rx51-sdram.c +++ b/arch/arm/mach-omap2/board-rx51-sdram.c @@ -67,57 +67,6 @@ static const struct sdram_info rx51_info = { .row_lines = 13, }; -#define CM_BASE0x48004000 - -#define CM_CLKSEL_CORE 0x0a40 -#define CM_CLKSEL1_PLL 0x0d40 - -#define PRM_CLKSEL 0x48306d40 -#define PRM_CLKSRC_CTRL 0x48307270 - -static u32 cm_base = CM_BASE; - -static inline u32 cm_read_reg(int idx) -{ - return *(u32 *)OMAP2_L4_IO_ADDRESS(cm_base + idx); -} - -static const unsigned long sys_clk_rate_table[] = { - 12000, 13000, 19200, 26000, 38400, 16800 -}; - -static unsigned long get_sys_clk_rate(void) -{ - unsigned long rate; - - rate = sys_clk_rate_table[*(u32 *)OMAP2_L4_IO_ADDRESS(PRM_CLKSEL) 0x07]; - if (((*(u32 *)OMAP2_L4_IO_ADDRESS(PRM_CLKSRC_CTRL) 6) 0x03) == 0x02) - rate /= 2; - return rate; -} - -static unsigned long get_core_rate(void) -{ - unsigned long rate; - u32 l; - - l = cm_read_reg(CM_CLKSEL1_PLL); - rate = get_sys_clk_rate(); - rate *= ((l 16) 0x7ff); - rate /= ((l 8) 0x7f) + 1; - rate /= (l 27) 0x1f; - - return rate; -} - -static unsigned long get_l3_rate(void) -{ - u32 l; - - l = cm_read_reg(CM_CLKSEL_CORE); - return get_core_rate() / (l 0x03); -} - static unsigned long sdrc_get_fclk_period(long rate) { /* In picoseconds */ -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] RX51: Add SDRAM init
From: Tero Kristo tero.kri...@nokia.com This patch adds board specific SDRAM init for RX51. This patch is a collaboration of work from following people: Juha Yrjola: Original code Lauri Leukkunen: Port to RX51 Tero Kristo: Support for multiple OPP:s, merge of patches Samu Onkalo: Fixed SDRAM parameters according to specs Kalle Jokiniemi: A fix for rounding error Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Samu Onkalo samu.p.onk...@nokia.com Cc: Kalle Jokiniemi kalle.jokini...@digia.com Cc: Lauri Leukkunen lauri.leukku...@nokia.com Cc: Juha Yrjola juha.yrj...@solidboot.com --- arch/arm/mach-omap2/Makefile |1 + arch/arm/mach-omap2/board-rx51-sdram.c | 221 arch/arm/mach-omap2/board-rx51.c |7 +- 3 files changed, 228 insertions(+), 1 deletions(-) create mode 100644 arch/arm/mach-omap2/board-rx51-sdram.c diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 03cb4fc..9cd745a 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \ mmc-twl4030.o obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ + board-rx51-sdram.o \ board-rx51-peripherals.o \ mmc-twl4030.o obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom2.o \ diff --git a/arch/arm/mach-omap2/board-rx51-sdram.c b/arch/arm/mach-omap2/board-rx51-sdram.c new file mode 100644 index 000..f392844 --- /dev/null +++ b/arch/arm/mach-omap2/board-rx51-sdram.c @@ -0,0 +1,221 @@ +/* + * SDRC register values for RX51 + * + * Copyright (C) 2008 Nokia Corporation + * + * Lauri Leukkunen lauri.leukku...@nokia.com + * + * Original code by Juha Yrjola juha.yrj...@solidboot.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include linux/kernel.h +#include linux/clk.h +#include linux/err.h +#include linux/io.h + +#include plat/io.h +#include plat/common.h +#include plat/clock.h +#include plat/sdrc.h + + +/* In picoseconds, except for tREF (ns), tXP, tCKE, tWTR (clks) */ +struct sdram_timings { + u32 casl; + u32 tDAL; + u32 tDPL; + u32 tRRD; + u32 tRCD; + u32 tRP; + u32 tRAS; + u32 tRC; + u32 tRFC; + u32 tXSR; + + u32 tREF; /* in ns */ + + u32 tXP; + u32 tCKE; + u32 tWTR; +}; + +struct omap_sdrc_params rx51_sdrc_params[4]; + +static const struct sdram_timings rx51_timings[] = { + { + .casl = 3, + .tDAL = 33000, + .tDPL = 15000, + .tRRD = 12000, + .tRCD = 22500, + .tRP = 18000, + .tRAS = 42000, + .tRC = 66000, + .tRFC = 138000, + .tXSR = 20, + + .tREF = 7800, + + .tXP = 2, + .tCKE = 2, + .tWTR = 2 + }, +}; + +static unsigned long sdrc_get_fclk_period(long rate) +{ + /* In picoseconds */ + return 10 / rate; +} + +static unsigned int sdrc_ps_to_ticks(unsigned int time_ps, long rate) +{ + unsigned long tick_ps; + + /* Calculate in picosecs to yield more exact results */ + tick_ps = sdrc_get_fclk_period(rate); + + return (time_ps + tick_ps - 1) / tick_ps; +} +#undef DEBUG +#ifdef DEBUG +static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, + int ticks, long rate, const char *name) +#else +static int set_sdrc_timing_regval(u32 *regval, int st_bit, int end_bit, + int ticks) +#endif +{ + int mask, nr_bits; + + nr_bits = end_bit - st_bit + 1; + if (ticks = 1 nr_bits) + return -1; + mask = (1 nr_bits) - 1; + *regval = ~(mask st_bit); + *regval |= ticks st_bit; +#ifdef DEBUG + printk(KERN_INFO SDRC %s: %i ticks %i ns\n, name, ticks, + (unsigned int)sdrc_get_fclk_period(rate) * ticks / + 1000); +#endif + + return 0; +} + +#ifdef DEBUG +#define SDRC_SET_ONE(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval((reg), (st), (end), \ + rx51_timings-field, (rate), #field) 0) \ + err = -1; +#else +#define SDRC_SET_ONE(reg, st, end, field, rate) \ + if (set_sdrc_timing_regval((reg), (st), (end), \ + rx51_timings-field) 0) \ + err = -1; +#endif + +#ifdef DEBUG +static int set_sdrc_timing_regval_ps(u32 *regval, int st_bit, int end_bit, + int time, long rate, const char
[PATCH] OMAP3: Clock: Fixed dpll3_m2x2 rate calculation
From: Tero Kristo tero.kri...@nokia.com Current calculation does not take into account any changes to M2 divisor, and thus when we change VDD2 OPP, dpll3_m2x2 rate does not change. Fixed by re-routing dpll3_m2x2 parent to dpll3_m2. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clock34xx.h |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index a1b3de7..8fe1bcb 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -489,9 +489,9 @@ static struct clk core_ck = { static struct clk dpll3_m2x2_ck = { .name = dpll3_m2x2_ck, .ops= clkops_null, - .parent = dpll3_x2_ck, + .parent = dpll3_m2_ck, .clkdm_name = dpll3_clkdm, - .recalc = followparent_recalc, + .recalc = omap3_clkoutx2_recalc, }; /* The PWRDN bit is apparently only available on 3430ES2 and above */ -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/5] OMAP3: Fixed ARM aux ctrl register save/restore
From: Tero Kristo tero.kri...@nokia.com Current value is stored on SDRAM and it is written back during wakeup. Previously a static value of 0x72 was written there. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/sleep34xx.S | 13 + 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index 4707ba8..8bd5fc5 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -278,7 +278,8 @@ restore: mov r1, #0 @ set task id for ROM code in r1 mov r2, #4 @ set some flags in r2, r6 mov r6, #0xff - adr r3, write_aux_control_params@ r3 points to parameters + ldr r4, scratchpad_base + ldr r3, [r4, #0xBC] @ r3 points to parameters mcr p15, 0, r0, c7, c10, 4 @ data write barrier mcr p15, 0, r0, c7, c10, 5 @ data memory barrier .word 0xE1600071 @ call SMI monitor (smi #1) @@ -286,14 +287,14 @@ restore: b logic_l1_restore l2_inv_api_params: .word 0x1, 0x00 -write_aux_control_params: - .word 0x1, 0x72 l2_inv_gp: /* Execute smi to invalidate L2 cache */ mov r12, #0x1 @ set up to invalide L2 smi:.word 0xE1600070 @ Call SMI monitor (smieq) /* Write to Aux control register to set some bits */ - mov r0, #0x72 + ldr r4, scratchpad_base + ldr r3, [r4,#0xBC] + ldr r0, [r3,#4] mov r12, #0x3 .word 0xE1600070@ Call SMI monitor (smieq) logic_l1_restore: @@ -304,6 +305,7 @@ logic_l1_restore: ldr r4, scratchpad_base ldr r3, [r4,#0xBC] + addsr3, r3, #8 ldmia r3!, {r4-r6} mov sp, r4 msr spsr_cxsf, r5 @@ -420,6 +422,9 @@ usettbr0: save_context_wfi: /*b save_context_wfi*/ @ enable to debug save code mov r8, r0 /* Store SDRAM address in r8 */ + mrc p15, 0, r5, c1, c0, 1 @ Read Auxiliary Control Register + mov r4, #0x1@ Number of parameters for restore call + stmia r8!, {r4-r5} /* Check what that target sleep state is:stored in r1*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost */ -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/5] OMAP3: PM: Write voltage and clock setup times dynamically in idle loop
From: Tero Kristo tero.kri...@nokia.com It is suggested by TI (SWPA152 February 2009) to write clksetup, voltsetup_time1, voltsetup_time2, voltsetup2 dynamically in idle loop. This allows us to optimize the voltage + clock setup times according to the used power save mode. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm.h | 10 - arch/arm/mach-omap2/pm34xx.c | 87 +++-- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index b576424..d10e0c1 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -24,12 +24,18 @@ extern int omap3_can_sleep(void); extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); extern int omap3_idle_init(void); -struct prm_setup_vc { +struct prm_setup_times_vc { u16 clksetup; u16 voltsetup_time1; u16 voltsetup_time2; - u16 voltoffset; u16 voltsetup2; + u16 voltsetup1; +}; + +struct prm_setup_vc { + struct prm_setup_times_vc *setup_times; + struct prm_setup_times_vc *setup_times_off; + u16 voltoffset; /* PRM_VC_CMD_VAL_0 specific bits */ u16 vdd0_on; u16 vdd0_onlp; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 796d726..2f9f4a0 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -82,12 +82,17 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; static struct powerdomain *cam_pwrdm; -static struct prm_setup_vc prm_setup = { +static struct prm_setup_times_vc prm_setup_times_default = { .clksetup = 0xff, .voltsetup_time1 = 0xfff, .voltsetup_time2 = 0xfff, - .voltoffset = 0xff, .voltsetup2 = 0xff, +}; + +static struct prm_setup_vc prm_setup_default = { + .setup_times = prm_setup_times_default, + .setup_times_off = NULL, + .voltoffset = 0xff, .vdd0_on = 0x30,/* 1.2v */ .vdd0_onlp = 0x20, /* 1.0v */ .vdd0_ret = 0x1e, /* 0.975v */ @@ -98,6 +103,8 @@ static struct prm_setup_vc prm_setup = { .vdd1_off = 0x00, /* 0.6v */ }; +static struct prm_setup_vc *prm_setup = prm_setup_default; + static inline void omap3_per_save_context(void) { omap_gpio_save_context(); @@ -338,6 +345,16 @@ static void restore_table_entry(void) restore_control_register(control_reg_value); } +static void prm_program_setup_times(struct prm_setup_times_vc *times) +{ + prm_write_mod_reg(times-voltsetup1, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTSETUP1_OFFSET); + prm_write_mod_reg(times-voltsetup2, OMAP3430_GR_MOD, + OMAP3_PRM_VOLTSETUP2_OFFSET); + prm_write_mod_reg(times-clksetup, OMAP3430_GR_MOD, + OMAP3_PRM_CLKSETUP_OFFSET); +} + void omap_sram_idle(void) { /* Variable to tell what needs to be saved and restored @@ -422,6 +439,9 @@ void omap_sram_idle(void) OMAP3_PRM_VOLTCTRL_OFFSET); omap3_core_save_context(); omap3_prcm_save_context(); + if (prm_setup-setup_times_off != NULL) + prm_program_setup_times(prm_setup- + setup_times_off); } else if (core_next_state == PWRDM_POWER_RET) { prm_set_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, @@ -479,11 +499,13 @@ void omap_sram_idle(void) } omap_uart_resume_idle(0); omap_uart_resume_idle(1); - if (core_next_state == PWRDM_POWER_OFF) + if (core_next_state == PWRDM_POWER_OFF) { prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); - else if (core_next_state == PWRDM_POWER_RET) + if (prm_setup-setup_times_off != NULL) + prm_program_setup_times(prm_setup-setup_times); + } else if (core_next_state == PWRDM_POWER_RET) prm_clear_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); @@ -1043,24 +1065,21 @@ int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) return -EINVAL; } +static void omap3_init_prm_setup_times(struct prm_setup_times_vc *conf) +{ + if (!conf) + return; + + conf-voltsetup1 = + (conf-voltsetup_time2 OMAP3430_SETUP_TIME2_SHIFT) | + (conf-voltsetup_time1 OMAP3430_SETUP_TIME1_SHIFT); +} + void
[PATCH 5/5] OMAP3: PM: Disable OTG autoidle when waking up from off-mode
From: Tero Kristo tero.kri...@nokia.com OMAP3 sleep can be prevented in some cases where OTG autoidle is enabled. This patch force disables autoidle during wakeup from off-mode. See omap errata 1.164. This fix can't be done in driver level, as off-mode entry resets and enables the autoidle bit, and driver does not access the register after each off-mode entry even if it is loaded. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c |6 ++ arch/arm/mach-omap2/usb-musb.c| 14 -- arch/arm/plat-omap/include/plat/usb.h |3 +++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 2f9f4a0..ab7b30f 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -37,6 +37,7 @@ #include plat/gpmc.h #include plat/dma.h #include plat/dmtimer.h +#include plat/usb.h #include plat/resource.h @@ -496,6 +497,11 @@ void omap_sram_idle(void) omap3_prcm_restore_context(); omap3_sram_restore_context(); omap2_sms_restore_context(); + /* +* Errata 1.164 fix : OTG autoidle can prevent +* sleep +*/ + usb_musb_disable_autoidle(); } omap_uart_resume_idle(0); omap_uart_resume_idle(1); diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index f5364b8..bb3cee4 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -44,10 +44,11 @@ static struct platform_device dummy_pdev = { }, }; +static void __iomem *otg_base; +static struct clk *otg_clk; + static void __init usb_musb_pm_init(void) { - void __iomem *otg_base; - struct clk *otg_clk; struct device *dev = dummy_pdev.dev; if (!cpu_is_omap34xx()) @@ -74,12 +75,13 @@ static void __init usb_musb_pm_init(void) cpu_relax(); } - if (otg_clk) { + if (otg_clk) clk_disable(otg_clk); - clk_put(otg_clk); - } +} - iounmap(otg_base); +void usb_musb_disable_autoidle(void) +{ + __raw_writel(0, otg_base + OTG_SYSCONFIG); } #ifdef CONFIG_USB_MUSB_SOC diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h index 33a500e..31b13bc 100644 --- a/arch/arm/plat-omap/include/plat/usb.h +++ b/arch/arm/plat-omap/include/plat/usb.h @@ -46,6 +46,9 @@ extern void usb_musb_init(void); extern void usb_ehci_init(struct ehci_hcd_omap_platform_data *pdata); +/* This is needed for OMAP3 errata 1.164: enabled autoidle can prevent sleep */ +extern void usb_musb_disable_autoidle(void); + #endif void omap_usb_init(struct omap_usb_config *pdata); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/5] OMAP3: PM: Added support for L2 aux ctrl register save and restore
From: Tero Kristo tero.kri...@nokia.com This patch adds a save and restore mechanism for ARM L2 auxiliary control register. The feature is enabled by default for GP devices, but for HS/EMU devices the user must enable the service and define the PPA service ID to be used for setting L2 aux ctrl, as this is not currently supported by the bootloader. If nobody alters the contents of L2 aux ctrl from its reset value, this feature is not needed. Kconfig option to enable HS/EMU L2 aux save and restore: - OMAP3_L2_AUX_SECURE_SAVE_RESTORE Kconfig option to select HS/EMU PPA service for setting L2 aux ctrl: - OMAP3_L2_AUX_SECURE_SERVICE_SET_ID Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/sleep34xx.S | 26 -- arch/arm/plat-omap/Kconfig | 17 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S index 8bd5fc5..69521be 100644 --- a/arch/arm/mach-omap2/sleep34xx.S +++ b/arch/arm/mach-omap2/sleep34xx.S @@ -284,6 +284,21 @@ restore: mcr p15, 0, r0, c7, c10, 5 @ data memory barrier .word 0xE1600071 @ call SMI monitor (smi #1) +#ifdef CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE + /* Restore L2 aux control register */ + @ set service ID for PPA + mov r0, #CONFIG_OMAP3_L2_AUX_SECURE_SERVICE_SET_ID + mov r12, r0 @ copy service ID in r12 + mov r1, #0 @ set task ID for ROM code in r1 + mov r2, #4 @ set some flags in r2, r6 + mov r6, #0xff + ldr r4, scratchpad_base + ldr r3, [r4, #0xBC] + addsr3, r3, #8 @ r3 points to parameters + mcr p15, 0, r0, c7, c10, 4 @ data write barrier + mcr p15, 0, r0, c7, c10, 5 @ data memory barrier + .word 0xE1600071 @ call SMI monitor (smi #1) +#endif b logic_l1_restore l2_inv_api_params: .word 0x1, 0x00 @@ -297,6 +312,11 @@ smi:.word 0xE1600070 @ Call SMI monitor (smieq) ldr r0, [r3,#4] mov r12, #0x3 .word 0xE1600070@ Call SMI monitor (smieq) + ldr r4, scratchpad_base + ldr r3, [r4,#0xBC] + ldr r0, [r3,#12] + mov r12, #0x2 + .word 0xE1600070@ Call SMI monitor (smieq) logic_l1_restore: mov r1, #0 /* Invalidate all instruction caches to PoU @@ -305,7 +325,7 @@ logic_l1_restore: ldr r4, scratchpad_base ldr r3, [r4,#0xBC] - addsr3, r3, #8 + addsr3, r3, #16 ldmia r3!, {r4-r6} mov sp, r4 msr spsr_cxsf, r5 @@ -424,7 +444,9 @@ save_context_wfi: mov r8, r0 /* Store SDRAM address in r8 */ mrc p15, 0, r5, c1, c0, 1 @ Read Auxiliary Control Register mov r4, #0x1@ Number of parameters for restore call - stmia r8!, {r4-r5} + stmia r8!, {r4-r5}@ Push parameters for restore call + mrc p15, 1, r5, c9, c0, 2 @ Read L2 AUX ctrl register + stmia r8!, {r4-r5}@ Push parameters for restore call /* Check what that target sleep state is:stored in r1*/ /* 1 - Only L1 and logic lost */ /* 2 - Only L2 lost */ diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 2143db5..3ff1a5f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -185,6 +185,23 @@ config OMAP3_DEBOBS help Use ETK pads for debug observability +config OMAP3_L2_AUX_SECURE_SAVE_RESTORE + bool OMAP3 HS/EMU save and restore for L2 AUX control register + depends on ARCH_OMAP3 PM + default n + help + Without this option, L2 Auxiliary control register contents are + lost during off-mode entry on HS/EMU devices. This feature + requires support from PPA / boot-loader in HS/EMU devices, which + currently does not exist by default. + +config OMAP3_L2_AUX_SECURE_SERVICE_SET_ID + int Service ID for the support routine to set L2 AUX control + depends on OMAP3_L2_AUX_SECURE_SAVE_RESTORE + default 43 + help + PPA routine service ID for setting L2 auxiliary control register. + config OMAP_32K_TIMER_HZ int Kernel internal timer frequency for 32KHz timer range 32 1024 -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 0/5] Misc fixes [for PM branch]
From: Tero Kristo tero.kri...@nokia.com This set contains following changes compared to previous one: 1) Removed accepted patches 2) ARM aux ctrl and L2 aux ctrl register save/restore uses now arm_context as save area 3) Added more detail to I2C4 repeated start disable fix description 4) Refreshed patches against PM branch -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/5] OMAP3: PM: Disabled I2C4 repeated start operation mode
From: Tero Kristo tero.kri...@nokia.com Repeated start forces I2C4 pads low during idle, which increases power consumption through external pull-ups. On the other hand, this change increases I2C4 command latencies somewhat due to additional master code sent in the beginning of each I2C4 command (8 bits data + start + ack bits in fast/standard mode = increases total command duration from 25us to 50us.) Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index b97f7d8..796d726 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -1221,7 +1221,7 @@ static void __init configure_vc(void) prm_write_mod_reg(OMAP3430_CMD1 | OMAP3430_RAV1, OMAP3430_GR_MOD, OMAP3_PRM_VC_CH_CONF_OFFSET); - prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN, + prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN, OMAP3430_GR_MOD, OMAP3_PRM_VC_I2C_CFG_OFFSET); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/6] Idle status patches revisited
From: Tero Kristo tero.kri...@nokia.com Following set implements checks for idle states of powerdomains, and changes target cpuidle state according to those. This also includes as a cleanup removal of some hacks from omap_sram_idle(), and also introduces INACTIVE / ON state support for powerdomains which simplifies the code. Applies on top of PM branch. -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/6] OMAP3: PM: Removed PER + CORE state hacking from omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com This should be moved inside cpuidle to simplify design. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 18 ++ 1 files changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 7b52f30..c704756 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -81,7 +81,6 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; -static struct powerdomain *cam_pwrdm; static struct prm_setup_times_vc prm_setup_times_default = { .clksetup = 0xff, @@ -370,7 +369,6 @@ void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -409,19 +407,10 @@ void omap_sram_idle(void) if (per_next_state PWRDM_POWER_ON) { omap_uart_prepare_idle(2); omap2_gpio_prepare_for_idle(per_next_state); - if (per_next_state == PWRDM_POWER_OFF) { - if (core_next_state == PWRDM_POWER_ON) { - per_next_state = PWRDM_POWER_RET; - pwrdm_set_next_pwrst(per_pwrdm, per_next_state); - per_state_modified = 1; - } else - omap3_per_save_context(); - } + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); } - if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) - omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* * Disable smartreflex before entering WFI. * Only needed if we are going to enter retention or off. @@ -540,8 +529,6 @@ void omap_sram_idle(void) omap3_gpio_restore_pad_context(1); omap2_gpio_resume_after_idle(); omap_uart_resume_idle(2); - if (per_state_modified) - pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -1170,7 +1157,6 @@ static 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); omap_push_sram_idle(); #ifdef CONFIG_SUSPEND -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/6] OMAP3: PM: Added support for INACTIVE and ON states for powerdomains
From: Tero Kristo tero.kri...@nokia.com Previously omap_sram_idle() did not know about the difference between ON and INACTIVE states, which complicated the state handling in these cases. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 14 +++--- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 9d0a9b4..7b52f30 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -383,6 +383,7 @@ void omap_sram_idle(void) mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -448,9 +449,11 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } - /* Enable IO-PAD and IO-CHAIN wakeups */ - prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); - omap3_enable_io_chain(); + if (core_next_state = PWRDM_POWER_RET) { + /* Enable IO-PAD and IO-CHAIN wakeups */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); + } } omap3_intc_prepare_idle(); @@ -542,15 +545,13 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (core_next_state PWRDM_POWER_ON) { + if (core_next_state = PWRDM_POWER_ON) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } pwrdm_post_transition(); - - omap2_clkdm_allow_idle(mpu_pwrdm-pwrdm_clkdms[0]); } int omap3_can_sleep(void) @@ -598,7 +599,6 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) } if (sleep_switch) { - omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/6] OMAP3: CPUidle: Added peripheral pwrdm checks into bm check
From: Tero Kristo tero.kri...@nokia.com Following checks are made (and their reasoning): - If CAM domain is active, prevent idle completely * CAM pwrdm does not have HW wakeup capability - If PER is likely to remain on, prevent PER off * Saves on unnecessary context save/restore - If CORE domain is active, prevent PER off-mode * PER off in this case would prevent wakeups from PER completely - Only allow CORE off, if all peripheral domains are off * CORE off will cause a chipwide reset Also, enabled CHECK_BM flag for C2, as this is needed for the camera case. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 105 ++--- 1 files changed, 98 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index e46345f..4654e87 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -58,7 +58,8 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd; +struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd; +struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd; /* * The latencies/thresholds for various C states have @@ -91,6 +92,13 @@ static int omap3_idle_bm_check(void) return 0; } +static int pwrdm_get_idle_state(struct powerdomain *pwrdm) +{ + if (pwrdm_can_idle(pwrdm)) + return pwrdm_read_next_pwrst(pwrdm); + return PWRDM_POWER_ON; +} + /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -153,14 +161,90 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; - - if ((state-flags CPUIDLE_FLAG_CHECK_BM) omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); - new_state = dev-safe_state; + u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; + u32 iva2_state, sgx_state, dss_state, new_core_state; + struct omap3_processor_cx *cx; + int ret; + + if (state-flags CPUIDLE_FLAG_CHECK_BM) { + if (omap3_idle_bm_check()) { + BUG_ON(!dev-safe_state); + new_state = dev-safe_state; + goto select_state; + } + cx = cpuidle_get_statedata(state); + new_core_state = cx-core_state; + + /* Check if CORE is active, if yes, fallback to inactive */ + if (!pwrdm_can_idle(core_pd)) + new_core_state = PWRDM_POWER_INACTIVE; + + /* +* Prevent idle completely if CAM is active. +* CAM does not have wakeup capability in OMAP3. +*/ + cam_state = pwrdm_get_idle_state(cam_pd); + if (cam_state == PWRDM_POWER_ON) { + new_state = dev-safe_state; + goto select_state; + } + + /* +* Check if PER can idle or not. If we are not likely +* to idle, deny PER off. This prevents unnecessary +* context save/restore. +*/ + saved_per_state = pwrdm_read_next_pwrst(per_pd); + if (pwrdm_can_idle(per_pd)) { + per_state = saved_per_state; + /* +* Prevent PER off if CORE is active as this +* would disable PER wakeups completely +*/ + if (per_state == PWRDM_POWER_OFF + new_core_state PWRDM_POWER_RET) + per_state = PWRDM_POWER_RET; + + } else if (saved_per_state == PWRDM_POWER_OFF) + per_state = PWRDM_POWER_RET; + + /* +* If we are attempting CORE off, check if any other +* powerdomains are at retention or higher. CORE off causes +* chipwide reset which would reset these domains also. +*/ + if (new_core_state == PWRDM_POWER_OFF) { + dss_state = pwrdm_get_idle_state(dss_pd); + iva2_state = pwrdm_get_idle_state(iva2_pd); + sgx_state = pwrdm_get_idle_state(sgx_pd); + usb_state = pwrdm_get_idle_state(usb_pd); + + if (cam_state PWRDM_POWER_OFF || + dss_state PWRDM_POWER_OFF || + iva2_state PWRDM_POWER_OFF || + per_state PWRDM_POWER_OFF || + sgx_state PWRDM_POWER_OFF || + usb_state PWRDM_POWER_OFF
[PATCH 1/6] OMAP: Powerdomains: Add support for INACTIVE state on pwrdm level
From: Tero Kristo tero.kri...@nokia.com Currently only ON, RET and OFF are supported, and ON is arguably broken as it allows the powerdomain to enter INACTIVE state unless idle is prevented. Now, pwrdm code prevents idle if ON is selected, and also adds support for INACTIVE. This simplifies the control needed inside sleep code. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/powerdomain.c | 32 + arch/arm/mach-omap2/powerdomains34xx.h| 26 ++-- arch/arm/plat-omap/include/plat/powerdomain.h |6 - 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index b6990e3..1237717 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -112,8 +112,8 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev; - int state; + u8 prev; + u8 state; if (pwrdm == NULL) return -EINVAL; @@ -220,7 +220,7 @@ int pwrdm_register(struct powerdomain *pwrdm) pr_debug(powerdomain: registered %s\n, pwrdm-name); ret = 0; - + pwrdm-next_state = -1; pr_unlock: write_unlock_irqrestore(pwrdm_rwlock, flags); @@ -701,19 +701,38 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) */ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) { + u8 prg_pwrst; + if (!pwrdm) return -EINVAL; + if (pwrdm-next_state == pwrst) + return 0; + if (!(pwrdm-pwrsts (1 pwrst))) return -EINVAL; pr_debug(powerdomain: setting next powerstate for %s to %0x\n, pwrdm-name, pwrst); + /* INACTIVE is reserved, so we program pwrdm as ON */ + if (pwrst == PWRDM_POWER_INACTIVE) + prg_pwrst = PWRDM_POWER_ON; + else + prg_pwrst = pwrst; + prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, -(pwrst OMAP_POWERSTATE_SHIFT), +(prg_pwrst OMAP_POWERSTATE_SHIFT), pwrdm-prcm_offs, PM_PWSTCTRL); + /* If next state is ON, prevent idle */ + if (pwrst == PWRDM_POWER_ON) + omap2_clkdm_deny_idle(pwrdm-pwrdm_clkdms[0]); + else + omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); + + pwrdm-next_state = pwrst; + return 0; } @@ -730,8 +749,11 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; + if (pwrdm-next_state -1) + return pwrdm-next_state; + return prm_read_mod_bits_shift(pwrdm-prcm_offs, PM_PWSTCTRL, - OMAP_POWERSTATE_MASK); + OMAP_POWERSTATE_MASK); } /** diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index fd09b08..9eb2dc5 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -165,7 +165,7 @@ static struct powerdomain iva2_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, .wkdep_srcs = iva2_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks= 4, .pwrsts_mem_ret = { @@ -188,7 +188,7 @@ static struct powerdomain mpu_34xx_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_EN_MPU_SHIFT, .wkdep_srcs = mpu_34xx_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks= 1, .pwrsts_mem_ret = { @@ -206,7 +206,7 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0), - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .dep_bit = OMAP3430_EN_CORE_SHIFT, .banks= 2, .pwrsts_mem_ret = { @@ -214,8 +214,8 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { [1] = PWRSTS_OFF_RET,/* MEM2RETSTATE */ }, .pwrsts_mem_on= { - [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ - [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ + [0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */ + [1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE
[PATCH 3/6] OMAP3: CPUidle: Fixed support for ON / INACTIVE states
From: Tero Kristo tero.kri...@nokia.com New powerdomain code support for INACTIVE state removes the need to control clockdomains directly from cpuidle. Also, cpuidle state definitions can now directly support ON / INACTIVE simplifying the implementation. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 32 1 files changed, 4 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index fdfa1d5..e46345f 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -91,20 +91,6 @@ static int omap3_idle_bm_check(void) return 0; } -static int _cpuidle_allow_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_allow_idle(clkdm); - return 0; -} - -static int _cpuidle_deny_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_deny_idle(clkdm); - return 0; -} - /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -141,19 +127,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); - } - /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); - } - return_sleep_time: getnstimeofday(ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); @@ -242,8 +218,8 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[OMAP3_STATE_C2].threshold = cpuidle_params_table[OMAP3_STATE_C2].threshold; - omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; /* C3 . MPU CSWR + Core inactive */ @@ -256,7 +232,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; - omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; @@ -270,7 +246,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; - omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/6] OMAP: Powerdomains: Add support for checking if pwrdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking the current fclk enable bits. This call can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/powerdomain.c | 22 ++ arch/arm/mach-omap2/powerdomains34xx.h| 14 ++ arch/arm/plat-omap/include/plat/powerdomain.h |9 + 3 files changed, 45 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 1237717..bf2b97a 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1217,6 +1217,28 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) return 0; } +/** + * pwrdm_can_idle - check if the powerdomain can enter idle + * @pwrdm: struct powerdomain * the powerdomain to check status of + * + * Does a functional clock check for the powerdomain and returns 1 if the + * powerdomain can enter idle, 0 if not. + */ +int pwrdm_can_idle(struct powerdomain *pwrdm) +{ + int i; + const int fclk_regs[] = { CM_FCLKEN, OMAP3430ES2_CM_FCLKEN3 }; + + if (!pwrdm) + return -EINVAL; + + for (i = 0; i pwrdm-fclk_reg_amt; i++) + if (cm_read_mod_reg(pwrdm-prcm_offs, fclk_regs[i]) + (0x ^ pwrdm-fclk_masks[i])) + return 0; + return 1; +} + int pwrdm_state_switch(struct powerdomain *pwrdm) { return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index 9eb2dc5..c8cd297 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -180,6 +180,7 @@ static struct powerdomain iva2_pwrdm = { [2] = PWRSTS_OFF_ON, [3] = PWRDM_POWER_ON, }, + .fclk_reg_amt = 1, }; static struct powerdomain mpu_34xx_pwrdm = { @@ -236,6 +237,11 @@ static struct powerdomain core_34xx_es3_1_pwrdm = { [0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */ [1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE */ }, + .fclk_reg_amt = 2, + .fclk_masks = { + [0] = OMAP3430_EN_UART2 | OMAP3430_EN_UART1, + [1] = 0, + }, }; /* Another case of bit name collisions between several registers: EN_DSS */ @@ -255,6 +261,7 @@ static struct powerdomain dss_pwrdm = { .pwrsts_mem_on= { [0] = PWRDM_POWER_ON, /* MEMONSTATE */ }, + .fclk_reg_amt = 1, }; /* @@ -278,6 +285,7 @@ static struct powerdomain sgx_pwrdm = { .pwrsts_mem_on= { [0] = PWRDM_POWER_ON, /* MEMONSTATE */ }, + .fclk_reg_amt = 1, }; static struct powerdomain cam_pwrdm = { @@ -295,6 +303,7 @@ static struct powerdomain cam_pwrdm = { .pwrsts_mem_on= { [0] = PWRDM_POWER_ON, /* MEMONSTATE */ }, + .fclk_reg_amt = 1, }; static struct powerdomain per_pwrdm = { @@ -313,6 +322,10 @@ static struct powerdomain per_pwrdm = { .pwrsts_mem_on= { [0] = PWRDM_POWER_ON, /* MEMONSTATE */ }, + .fclk_reg_amt = 1, + .fclk_masks = { + [0] = OMAP3430_EN_UART3, + }, }; static struct powerdomain emu_pwrdm = { @@ -352,6 +365,7 @@ static struct powerdomain usbhost_pwrdm = { .pwrsts_mem_on= { [0] = PWRDM_POWER_ON, /* MEMONSTATE */ }, + .fclk_reg_amt = 1, }; static struct powerdomain dpll1_pwrdm = { diff --git a/arch/arm/plat-omap/include/plat/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h index 55350d0..b004d88 100644 --- a/arch/arm/plat-omap/include/plat/powerdomain.h +++ b/arch/arm/plat-omap/include/plat/powerdomain.h @@ -57,6 +57,12 @@ */ #define PWRDM_MAX_CLKDMS 4 +/* + * Maximum number of FCLK register masks that can be associated with a + * powerdomain. CORE powerdomain on OMAP3 is the worst case + */ +#define PWRDM_MAX_FCLK 2 + /* XXX A completely arbitrary number. What is reasonable here? */ #define PWRDM_TRANSITION_BAILOUT 10 @@ -124,6 +130,8 @@ struct powerdomain { s8 next_state; unsigned state_counter[4]; + u8 fclk_reg_amt; + u32 fclk_masks[PWRDM_MAX_FCLK]; #ifdef CONFIG_PM_DEBUG s64 timer; s64 state_timer[4]; @@ -177,6 +185,7 @@ int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); int pwrdm_wait_transition(struct powerdomain *pwrdm); +int pwrdm_can_idle(struct powerdomain *pwrdm); int pwrdm_state_switch(struct
[PATCH 0/2] VFP context save/restore support for OMAP3
From: Tero Kristo tero.kri...@nokia.com These two patches add support for VFP context save and restore. These patches are a collaboration from several people (listed in CC), I have mainly split the original patch in two parts (one generic ARM, one for OMAP3 PM), and optimized the code a bit. No sign-offs added from anybody except myself at the moment because I have modified the patches quite heavily. I think patch #1 should actually go to linux-arm list, however I thought to get some comments about the patches on omap list first. These will apply on top of PM branch. -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] OMAP3: Implemented VFP restore/save context
From: Tero Kristo tero.kri...@nokia.com VFP save context is called before MPU/NEON off. Restore is not needed as the next VFP trap will restore context automatically. Uses the support routine implemented in arch/arm/vfp/vfpmodule.c. Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Vishwanath Sripathy vishwanath...@ti.com Cc: Rajendra Nayak rna...@ti.com Cc: Richard Woodruff r-woodru...@ti.com Cc: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/mach-omap2/pm.h |1 + arch/arm/mach-omap2/pm34xx.c | 21 - 2 files changed, 21 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 4f22107..dd5bbaf 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -18,6 +18,7 @@ extern u32 sleep_while_idle; extern u32 voltage_off_while_idle; extern void *omap3_secure_ram_storage; +extern void vfp_pm_save_context(void); extern void omap3_pm_off_mode_enable(int); extern void omap_sram_idle(void); extern int omap3_can_sleep(void); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index b26ae5b..4b01303 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -321,6 +321,18 @@ static void restore_control_register(u32 val) __asm__ __volatile__ (mcr p15, 0, %0, c1, c0, 0 : : r (val)); } +static inline void omap3_save_neon_context(void) +{ +#ifdef CONFIG_VFP + vfp_pm_save_context(); +#endif +} + +static inline void omap3_restore_neon_context(void) +{ + return; +} + /* Function to restore the table entry that was modified for enabling MMU */ static void restore_table_entry(void) { @@ -365,6 +377,7 @@ void omap_sram_idle(void) /* save_state = 3 = L1, L2 and logic lost */ int save_state = 0; int mpu_next_state = PWRDM_POWER_ON; + int neon_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; @@ -398,8 +411,12 @@ void omap_sram_idle(void) pwrdm_pre_transition(); /* NEON control */ - if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) + if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) { pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); + neon_next_state = mpu_next_state; + if (neon_next_state == PWRDM_POWER_OFF) + omap3_save_neon_context(); + } /* PER */ per_next_state = pwrdm_read_next_pwrst(per_pwrdm); @@ -537,6 +554,8 @@ void omap_sram_idle(void) omap3_disable_io_chain(); } + if (neon_next_state == PWRDM_POWER_OFF) + omap3_restore_neon_context(); pwrdm_post_transition(); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] ARM: Implemented support for VFP PM context saving
From: Tero Kristo tero.kri...@nokia.com In some ARM architectures, like OMAP3, the VFP context can be lost during dynamic sleep cycle. For this purpose, there is now a function vfp_pm_save_context() that should be called before the VFP is assumed to lose context. Next VFP trap will then restore context automatically. We need to have the last_VFP_context[cpu] cleared after the save in idle, else the restore would fail to restore when it sees that the last_VFP_context is same as the current threads vfp_state. This happens when the same process/thread traps an exception post idle. Main work for this patch was done by Peter and Rajendra. Some cleanup and optimization by Tero. Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Vishwanath Sripathy vishwanath...@ti.com Cc: Rajendra Nayak rna...@ti.com Cc: Richard Woodruff r-woodru...@ti.com Cc: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/vfp/vfpmodule.c | 25 + 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 2d7423a..80a08bd 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -329,6 +329,31 @@ static void vfp_enable(void *unused) #ifdef CONFIG_PM #include linux/sysdev.h +void vfp_pm_save_context(void) +{ + struct thread_info *thread = current_thread_info(); + u32 fpexc = fmrx(FPEXC); + __u32 cpu = thread-cpu; + + if (last_VFP_context[cpu]) { + if (!(fpexc FPEXC_EN)) { + /* enable vfp now to save context */ + vfp_enable(NULL); + fmxr(FPEXC, fmrx(FPEXC) | FPEXC_EN); + } + vfp_save_state(last_VFP_context[cpu], fpexc); + + /* Disable vfp. The next inst traps an exception and restores*/ + fmxr(FPEXC, fmrx(FPEXC) ~FPEXC_EN); + + /* +* This is needed else the restore might fail if it sees +* last_VFP_context if same as the current threads vfp_state. +*/ + last_VFP_context[cpu] = NULL; + } +} + static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) { struct thread_info *ti = current_thread_info(); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] OMAP3: Implemented VFP restore/save context
From: Tero Kristo tero.kri...@nokia.com VFP save context is called before MPU/NEON off. Restore is not needed as the next VFP trap will restore context automatically. Uses the support routine implemented in arch/arm/vfp/vfpmodule.c. Signed-off-by: Tero Kristo tero.kri...@nokia.com Acked-by: Tony Lindgren t...@atomide.com Cc: Vishwanath Sripathy vishwanath...@ti.com Cc: Rajendra Nayak rna...@ti.com Cc: Richard Woodruff r-woodru...@ti.com Cc: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/mach-omap2/pm.h |1 + arch/arm/mach-omap2/pm34xx.c | 21 - 2 files changed, 21 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 4f22107..dd5bbaf 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -18,6 +18,7 @@ extern u32 sleep_while_idle; extern u32 voltage_off_while_idle; extern void *omap3_secure_ram_storage; +extern void vfp_pm_save_context(void); extern void omap3_pm_off_mode_enable(int); extern void omap_sram_idle(void); extern int omap3_can_sleep(void); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index b26ae5b..4b01303 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -321,6 +321,18 @@ static void restore_control_register(u32 val) __asm__ __volatile__ (mcr p15, 0, %0, c1, c0, 0 : : r (val)); } +static inline void omap3_save_neon_context(void) +{ +#ifdef CONFIG_VFP + vfp_pm_save_context(); +#endif +} + +static inline void omap3_restore_neon_context(void) +{ + return; +} + /* Function to restore the table entry that was modified for enabling MMU */ static void restore_table_entry(void) { @@ -365,6 +377,7 @@ void omap_sram_idle(void) /* save_state = 3 = L1, L2 and logic lost */ int save_state = 0; int mpu_next_state = PWRDM_POWER_ON; + int neon_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; @@ -398,8 +411,12 @@ void omap_sram_idle(void) pwrdm_pre_transition(); /* NEON control */ - if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) + if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) { pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); + neon_next_state = mpu_next_state; + if (neon_next_state == PWRDM_POWER_OFF) + omap3_save_neon_context(); + } /* PER */ per_next_state = pwrdm_read_next_pwrst(per_pwrdm); @@ -537,6 +554,8 @@ void omap_sram_idle(void) omap3_disable_io_chain(); } + if (neon_next_state == PWRDM_POWER_OFF) + omap3_restore_neon_context(); pwrdm_post_transition(); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2] VFP save/restore for OMAP3
From: Tero Kristo tero.kri...@nokia.com Hi, The following two patches are needed by OMAP3 to save/restore VFP context during off-mode. Patch 1 adds generic support inside ARM VFP code, and the second one adds the necessary hooks into OMAP3 power management code. --Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] ARM: Implemented support for VFP PM context saving
From: Tero Kristo tero.kri...@nokia.com In some ARM architectures, like OMAP3, the VFP context can be lost during dynamic sleep cycle. For this purpose, there is now a function vfp_pm_save_context() that should be called before the VFP is assumed to lose context. Next VFP trap will then restore context automatically. We need to have the last_VFP_context[cpu] cleared after the save in idle, else the restore would fail to restore when it sees that the last_VFP_context is same as the current threads vfp_state. This happens when the same process/thread traps an exception post idle. Main work for this patch was done by Peter and Rajendra. Some cleanup and optimization by Tero. Signed-off-by: Tero Kristo tero.kri...@nokia.com Acked-by: Tony Lindgren t...@atomide.com Cc: Vishwanath Sripathy vishwanath...@ti.com Cc: Rajendra Nayak rna...@ti.com Cc: Richard Woodruff r-woodru...@ti.com Cc: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/vfp/vfpmodule.c | 25 + 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 2d7423a..80a08bd 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -329,6 +329,31 @@ static void vfp_enable(void *unused) #ifdef CONFIG_PM #include linux/sysdev.h +void vfp_pm_save_context(void) +{ + struct thread_info *thread = current_thread_info(); + u32 fpexc = fmrx(FPEXC); + __u32 cpu = thread-cpu; + + if (last_VFP_context[cpu]) { + if (!(fpexc FPEXC_EN)) { + /* enable vfp now to save context */ + vfp_enable(NULL); + fmxr(FPEXC, fmrx(FPEXC) | FPEXC_EN); + } + vfp_save_state(last_VFP_context[cpu], fpexc); + + /* Disable vfp. The next inst traps an exception and restores*/ + fmxr(FPEXC, fmrx(FPEXC) ~FPEXC_EN); + + /* +* This is needed else the restore might fail if it sees +* last_VFP_context if same as the current threads vfp_state. +*/ + last_VFP_context[cpu] = NULL; + } +} + static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) { struct thread_info *ti = current_thread_info(); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 2/2] OMAP3: Implemented VFP restore/save context
From: Tero Kristo tero.kri...@nokia.com VFP save context is called before MPU/NEON off. Restore is not needed as the next VFP trap will restore context automatically. Uses the support routine implemented in arch/arm/vfp/vfpmodule.c. Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Vishwanath Sripathy vishwanath...@ti.com Cc: Rajendra Nayak rna...@ti.com Cc: Richard Woodruff r-woodru...@ti.com Cc: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/mach-omap2/pm.h |1 + arch/arm/mach-omap2/pm34xx.c | 14 +- 2 files changed, 14 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index e0c94ea..bf9b7f9 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -23,6 +23,7 @@ extern void omap_sram_idle(void); extern int omap3_can_sleep(void); extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); extern int omap3_idle_init(void); +extern void vfp_pm_save_context(void); struct prm_setup_times_vc { u16 clksetup; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 009bc55..624a7af 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -321,6 +321,13 @@ static void restore_control_register(u32 val) __asm__ __volatile__ (mcr p15, 0, %0, c1, c0, 0 : : r (val)); } +static inline void omap3_save_neon_context(void) +{ +#ifdef CONFIG_VFP + vfp_pm_save_context(); +#endif +} + /* Function to restore the table entry that was modified for enabling MMU */ static void restore_table_entry(void) { @@ -365,6 +372,7 @@ void omap_sram_idle(void) /* save_state = 3 = L1, L2 and logic lost */ int save_state = 0; int mpu_next_state = PWRDM_POWER_ON; + int neon_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; @@ -398,8 +406,12 @@ void omap_sram_idle(void) pwrdm_pre_transition(); /* NEON control */ - if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) + if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) { pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); + neon_next_state = mpu_next_state; + if (neon_next_state == PWRDM_POWER_OFF) + omap3_save_neon_context(); + } /* PER */ per_next_state = pwrdm_read_next_pwrst(per_pwrdm); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 1/2] ARM: VFP: Fixed suspend and added context save support
From: Tero Kristo tero.kri...@nokia.com In some ARM architectures, like OMAP3, the VFP context can be lost during dynamic sleep cycle. For this purpose, there is now a function vfp_pm_save_context() that should be called before the VFP is assumed to lose context. Next VFP trap will then restore context automatically. We need to have the last_VFP_context[cpu] cleared after the save in idle, else the restore would fail to restore when it sees that the last_VFP_context is same as the current threads vfp_state. This happens when the same process/thread traps an exception post idle. This patch also fixes a potential problem with vfp_pm_suspend(), where VFP context can be lost if the current process does not have VFP enabled. Fixed by calling vfp_pm_save_context(). Signed-off-by: Tero Kristo tero.kri...@nokia.com Cc: Vishwanath Sripathy vishwanath...@ti.com Cc: Rajendra Nayak rna...@ti.com Cc: Richard Woodruff r-woodru...@ti.com Cc: Peter 'p2' De Schrijver peter.de-schrij...@nokia.com --- arch/arm/vfp/vfpmodule.c | 28 1 files changed, 20 insertions(+), 8 deletions(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 2d7423a..920a33b 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -329,22 +329,34 @@ static void vfp_enable(void *unused) #ifdef CONFIG_PM #include linux/sysdev.h -static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) +void vfp_pm_save_context(void) { - struct thread_info *ti = current_thread_info(); u32 fpexc = fmrx(FPEXC); + unsigned int cpu = get_cpu(); + + /* Save last_VFP_context if needed */ + if (last_VFP_context[cpu]) { + /* Enable vfp to save context */ + if (!(fpexc FPEXC_EN)) { + vfp_enable(NULL); + fmxr(FPEXC, fpexc | FPEXC_EN); + } - /* if vfp is on, then save state for resumption */ - if (fpexc FPEXC_EN) { printk(KERN_DEBUG %s: saving vfp state\n, __func__); - vfp_save_state(ti-vfpstate, fpexc); + vfp_save_state(last_VFP_context[cpu], fpexc); /* disable, just in case */ - fmxr(FPEXC, fmrx(FPEXC) ~FPEXC_EN); + fmxr(FPEXC, fpexc ~FPEXC_EN); + + last_VFP_context[cpu] = NULL; } - /* clear any information we had about last context state */ - memset(last_VFP_context, 0, sizeof(last_VFP_context)); + put_cpu(); +} + +static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) +{ + vfp_pm_save_context(); return 0; } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 0/2] VFP context save/restore for OMAP3
From: Tero Kristo tero.kri...@nokia.com Contains following fixes compared to previous version: - vfp_pm_suspend uses the same routine as context save - uses get_cpu / put_cpu to get current CPU id - removed restore context call completely from OMAP3 idle (not needed) -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 2/6] OMAP3: PM: Added support for INACTIVE and ON states for powerdomains
From: Tero Kristo tero.kri...@nokia.com Previously omap_sram_idle() did not know about the difference between ON and INACTIVE states, which complicated the state handling in these cases. Now, the following changes are done in the idle logic: - Check for IO-chain arming is changed to reflect desired state (RET) - UART clocks will be disabled if we attempt to enter INACTIVE (this allows the state change to actually happen) Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 14 +++--- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 3b62c96..574492e 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -391,6 +391,7 @@ void omap_sram_idle(void) mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); switch (mpu_next_state) { case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: case PWRDM_POWER_RET: /* No need to save context */ save_state = 0; @@ -460,9 +461,11 @@ void omap_sram_idle(void) OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); } - /* Enable IO-PAD and IO-CHAIN wakeups */ - prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); - omap3_enable_io_chain(); + if (core_next_state = PWRDM_POWER_RET) { + /* Enable IO-PAD and IO-CHAIN wakeups */ + prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); + omap3_enable_io_chain(); + } } omap3_intc_prepare_idle(); @@ -561,15 +564,13 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (core_next_state PWRDM_POWER_ON) { + if (core_next_state = PWRDM_POWER_RET) { prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } pwrdm_post_transition(); - - omap2_clkdm_allow_idle(mpu_pwrdm-pwrdm_clkdms[0]); } int omap3_can_sleep(void) @@ -617,7 +618,6 @@ int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) } if (sleep_switch) { - omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); pwrdm_state_switch(pwrdm); } -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 0/6] Idle status patches revisited
From: Tero Kristo tero.kri...@nokia.com Improvements compared to previous set: - Fixed wrong pwrdm state check on IO chain arming on patch 2 - Improved changelog on patch 2 4 - Moved FCLK checks inside clockdomain code from powerdomain code in patch 5 - Some style changes on patch 6 Still, I believe there is no simple way of implementing the idle status check by using the usecounts inside clock framework. It would probably be possible by adding a new usecount variable that would be updated according to slightly different rules, but this also looks bit complicated compared to the need. -Tero -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 1/6] OMAP: Powerdomains: Add support for INACTIVE state on pwrdm level
From: Tero Kristo tero.kri...@nokia.com Currently only ON, RET and OFF are supported, and ON is arguably broken as it allows the powerdomain to enter INACTIVE state unless idle is prevented. Now, pwrdm code prevents idle if ON is selected, and also adds support for INACTIVE. This simplifies the control needed inside sleep code. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/powerdomain.c | 32 + arch/arm/mach-omap2/powerdomains34xx.h| 26 ++-- arch/arm/plat-omap/include/plat/powerdomain.h |6 - 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index b6990e3..1237717 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -112,8 +112,8 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev; - int state; + u8 prev; + u8 state; if (pwrdm == NULL) return -EINVAL; @@ -220,7 +220,7 @@ int pwrdm_register(struct powerdomain *pwrdm) pr_debug(powerdomain: registered %s\n, pwrdm-name); ret = 0; - + pwrdm-next_state = -1; pr_unlock: write_unlock_irqrestore(pwrdm_rwlock, flags); @@ -701,19 +701,38 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) */ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) { + u8 prg_pwrst; + if (!pwrdm) return -EINVAL; + if (pwrdm-next_state == pwrst) + return 0; + if (!(pwrdm-pwrsts (1 pwrst))) return -EINVAL; pr_debug(powerdomain: setting next powerstate for %s to %0x\n, pwrdm-name, pwrst); + /* INACTIVE is reserved, so we program pwrdm as ON */ + if (pwrst == PWRDM_POWER_INACTIVE) + prg_pwrst = PWRDM_POWER_ON; + else + prg_pwrst = pwrst; + prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, -(pwrst OMAP_POWERSTATE_SHIFT), +(prg_pwrst OMAP_POWERSTATE_SHIFT), pwrdm-prcm_offs, PM_PWSTCTRL); + /* If next state is ON, prevent idle */ + if (pwrst == PWRDM_POWER_ON) + omap2_clkdm_deny_idle(pwrdm-pwrdm_clkdms[0]); + else + omap2_clkdm_allow_idle(pwrdm-pwrdm_clkdms[0]); + + pwrdm-next_state = pwrst; + return 0; } @@ -730,8 +749,11 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) if (!pwrdm) return -EINVAL; + if (pwrdm-next_state -1) + return pwrdm-next_state; + return prm_read_mod_bits_shift(pwrdm-prcm_offs, PM_PWSTCTRL, - OMAP_POWERSTATE_MASK); + OMAP_POWERSTATE_MASK); } /** diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h index fd09b08..9eb2dc5 100644 --- a/arch/arm/mach-omap2/powerdomains34xx.h +++ b/arch/arm/mach-omap2/powerdomains34xx.h @@ -165,7 +165,7 @@ static struct powerdomain iva2_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT, .wkdep_srcs = iva2_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks= 4, .pwrsts_mem_ret = { @@ -188,7 +188,7 @@ static struct powerdomain mpu_34xx_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430), .dep_bit = OMAP3430_EN_MPU_SHIFT, .wkdep_srcs = mpu_34xx_wkdeps, - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, .banks= 1, .pwrsts_mem_ret = { @@ -206,7 +206,7 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { .omap_chip= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 | CHIP_IS_OMAP3430ES2 | CHIP_IS_OMAP3430ES3_0), - .pwrsts = PWRSTS_OFF_RET_ON, + .pwrsts = PWRSTS_OFF_RET_INA_ON, .dep_bit = OMAP3430_EN_CORE_SHIFT, .banks= 2, .pwrsts_mem_ret = { @@ -214,8 +214,8 @@ static struct powerdomain core_34xx_pre_es3_1_pwrdm = { [1] = PWRSTS_OFF_RET,/* MEM2RETSTATE */ }, .pwrsts_mem_on= { - [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ - [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ + [0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */ + [1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE
[PATCHv2 4/6] OMAP3: PM: Removed pwrdm state hacking from omap_sram_idle
From: Tero Kristo tero.kri...@nokia.com Following hacks will be moved inside cpuidle in subsequent patch: - CAM domain prevents idle completely - PER should not go OFF if core remains active This simplifies the design and allows cpuidle to keep better track of which power states system will actually enter. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/pm34xx.c | 18 ++ 1 files changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 574492e..d77fc88 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -81,7 +81,6 @@ static int (*_omap_save_secure_sram)(u32 *addr); static struct powerdomain *mpu_pwrdm, *neon_pwrdm; static struct powerdomain *core_pwrdm, *per_pwrdm; -static struct powerdomain *cam_pwrdm; static struct prm_setup_times_vc prm_setup_times_default = { .clksetup = 0xff, @@ -378,7 +377,6 @@ void omap_sram_idle(void) int core_next_state = PWRDM_POWER_ON; int core_prev_state, per_prev_state; u32 sdrc_pwr = 0; - int per_state_modified = 0; if (!_omap_sram_idle) return; @@ -421,19 +419,10 @@ void omap_sram_idle(void) if (per_next_state PWRDM_POWER_ON) { omap_uart_prepare_idle(2); omap2_gpio_prepare_for_idle(per_next_state); - if (per_next_state == PWRDM_POWER_OFF) { - if (core_next_state == PWRDM_POWER_ON) { - per_next_state = PWRDM_POWER_RET; - pwrdm_set_next_pwrst(per_pwrdm, per_next_state); - per_state_modified = 1; - } else - omap3_per_save_context(); - } + if (per_next_state == PWRDM_POWER_OFF) + omap3_per_save_context(); } - if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) - omap2_clkdm_deny_idle(mpu_pwrdm-pwrdm_clkdms[0]); - /* * Disable smartreflex before entering WFI. * Only needed if we are going to enter retention or off. @@ -559,8 +548,6 @@ void omap_sram_idle(void) } omap2_gpio_resume_after_idle(); omap_uart_resume_idle(2); - if (per_state_modified) - pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -1174,7 +1161,6 @@ static 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); omap_push_sram_idle(); #ifdef CONFIG_SUSPEND -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 5/6] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle
From: Tero Kristo tero.kri...@nokia.com pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter idle. This is done by checking all clockdomains under the powerdomain if they can idle also. omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can enter idle. This checks the functional clock status in the clockdomain. These calls can be used e.g. inside cpuidle to decide which power states core and mpu should enter during idle, as there are certain dependencies between wakeup capabilities and reset logic. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/clockdomain.c | 24 arch/arm/mach-omap2/clockdomains.h| 14 ++ arch/arm/mach-omap2/powerdomain.c | 25 + arch/arm/plat-omap/include/plat/clockdomain.h | 12 arch/arm/plat-omap/include/plat/powerdomain.h |1 + 5 files changed, 76 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index fcd8232..9ddeb96 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -474,6 +474,30 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) return 0; } + +/** + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not + * @clkdm: struct clockdomain * + * + * Checks if the clockdomain has any active clock or not, i.e. whether it + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle; + * 1 if can idle. + */ +int omap2_clkdm_can_idle(struct clockdomain *clkdm) +{ + int i; + const int fclk_regs[] = { CM_FCLKEN, OMAP3430ES2_CM_FCLKEN3 }; + + if (!clkdm) + return -EINVAL; + + for (i = 0; i clkdm-fclk_reg_amt; i++) + if (cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs, + fclk_regs[i]) ~clkdm-fclk_masks[i]) + return 0; + return 1; +} + /** * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm * @clkdm: struct clockdomain * diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h index c4ee076..2cde82a 100644 --- a/arch/arm/mach-omap2/clockdomains.h +++ b/arch/arm/mach-omap2/clockdomains.h @@ -167,6 +167,7 @@ static struct clockdomain iva2_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .fclk_reg_amt = 1, }; static struct clockdomain gfx_3430es1_clkdm = { @@ -183,6 +184,7 @@ static struct clockdomain sgx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .fclk_reg_amt = 1, }; /* @@ -206,6 +208,11 @@ static struct clockdomain core_l3_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .fclk_reg_amt = 2, + .fclk_masks = { + [0] = OMAP3430_EN_UART2 | OMAP3430_EN_UART1, + [1] = 0, + }, }; static struct clockdomain core_l4_34xx_clkdm = { @@ -222,6 +229,7 @@ static struct clockdomain dss_34xx_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .fclk_reg_amt = 1, }; static struct clockdomain cam_clkdm = { @@ -230,6 +238,7 @@ static struct clockdomain cam_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .fclk_reg_amt = 1, }; static struct clockdomain usbhost_clkdm = { @@ -238,6 +247,7 @@ static struct clockdomain usbhost_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2), + .fclk_reg_amt = 1, }; static struct clockdomain per_clkdm = { @@ -246,6 +256,10 @@ static struct clockdomain per_clkdm = { .flags = CLKDM_CAN_HWSUP_SWSUP, .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK, .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), + .fclk_reg_amt = 1, + .fclk_masks = { + [0] = OMAP3430_EN_UART3, + }, }; /* diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 1237717..2bef099 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1217,6 +1217,31 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) return 0; } +/** + * pwrdm_can_idle - check if the powerdomain can enter idle + * @pwrdm: struct
[PATCHv2 3/6] OMAP3: CPUidle: Fixed support for ON / INACTIVE states
From: Tero Kristo tero.kri...@nokia.com New powerdomain code support for INACTIVE state removes the need to control clockdomains directly from cpuidle. Also, cpuidle state definitions can now directly support ON / INACTIVE simplifying the implementation. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 32 1 files changed, 4 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 1cfa5a6..4a81ef1 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -91,20 +91,6 @@ static int omap3_idle_bm_check(void) return 0; } -static int _cpuidle_allow_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_allow_idle(clkdm); - return 0; -} - -static int _cpuidle_deny_idle(struct powerdomain *pwrdm, - struct clockdomain *clkdm) -{ - omap2_clkdm_deny_idle(clkdm); - return 0; -} - /** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device @@ -141,19 +127,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, if (omap_irq_pending() || need_resched()) goto return_sleep_time; - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); - } - /* Execute ARM wfi */ omap_sram_idle(); - if (cx-type == OMAP3_STATE_C1) { - pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); - pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); - } - return_sleep_time: getnstimeofday(ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); @@ -246,8 +222,8 @@ void omap_init_power_states(void) cpuidle_params_table[OMAP3_STATE_C2].wake_latency; omap3_power_states[OMAP3_STATE_C2].threshold = cpuidle_params_table[OMAP3_STATE_C2].threshold; - omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; - omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE; + omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; /* C3 . MPU CSWR + Core inactive */ @@ -261,7 +237,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C3].threshold = cpuidle_params_table[OMAP3_STATE_C3].threshold; omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET; - omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; @@ -276,7 +252,7 @@ void omap_init_power_states(void) omap3_power_states[OMAP3_STATE_C4].threshold = cpuidle_params_table[OMAP3_STATE_C4].threshold; omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF; - omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON; + omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_INACTIVE; omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_CHECK_BM; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv2 6/6] OMAP3: CPUidle: Added peripheral pwrdm checks into bm check
From: Tero Kristo tero.kri...@nokia.com Following checks are made (and their reasoning): - If CAM domain is active, prevent idle completely * CAM pwrdm does not have HW wakeup capability - If PER is likely to remain on, prevent PER off * Saves on unnecessary context save/restore - If CORE domain is active, prevent PER off-mode * PER off in this case would prevent wakeups from PER completely - Only allow CORE off, if all peripheral domains are off * CORE off will cause a chipwide reset Also, enabled CHECK_BM flag for C2, as this is needed for the camera case. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/cpuidle34xx.c | 118 ++-- 1 files changed, 111 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4a81ef1..dad64a9 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -58,7 +58,8 @@ struct omap3_processor_cx { struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; struct omap3_processor_cx current_cx_state; -struct powerdomain *mpu_pd, *core_pd; +struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd; +struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd; /* * The latencies/thresholds for various C states have @@ -92,6 +93,22 @@ static int omap3_idle_bm_check(void) } /** + * pwrdm_get_idle_state - Get the power state a pwrdm will enter during idle + * @pwrdm: powerdomain to check state for + * + * Checks if the powerdomain can enter idle or not, if yes, will return + * the programmed target state for the domain. Otherwise will indicate + * that the domain will stay on. + * Returns the power state the pwrdm will enter. + */ +static int pwrdm_get_idle_state(struct powerdomain *pwrdm) +{ + if (pwrdm_can_idle(pwrdm)) + return pwrdm_read_next_pwrst(pwrdm); + return PWRDM_POWER_ON; +} + +/** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device * @state: The target state to be programmed @@ -153,14 +170,94 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; - - if ((state-flags CPUIDLE_FLAG_CHECK_BM) omap3_idle_bm_check()) { - BUG_ON(!dev-safe_state); - new_state = dev-safe_state; + u32 per_state = 0, saved_per_state = 0, cam_state, usb_state; + u32 iva2_state, sgx_state, dss_state, new_core_state; + struct omap3_processor_cx *cx; + int ret; + + if (state-flags CPUIDLE_FLAG_CHECK_BM) { + if (omap3_idle_bm_check()) { + BUG_ON(!dev-safe_state); + new_state = dev-safe_state; + goto select_state; + } + cx = cpuidle_get_statedata(state); + new_core_state = cx-core_state; + + /* Check if CORE is active, if yes, fallback to inactive */ + if (!pwrdm_can_idle(core_pd)) + new_core_state = PWRDM_POWER_INACTIVE; + + /* +* Prevent idle completely if CAM is active. +* CAM does not have wakeup capability in OMAP3. +*/ + cam_state = pwrdm_get_idle_state(cam_pd); + if (cam_state == PWRDM_POWER_ON) { + new_state = dev-safe_state; + goto select_state; + } + + /* +* Check if PER can idle or not. If we are not likely +* to idle, deny PER off. This prevents unnecessary +* context save/restore. +*/ + saved_per_state = pwrdm_read_next_pwrst(per_pd); + if (pwrdm_can_idle(per_pd)) { + per_state = saved_per_state; + /* +* Prevent PER off if CORE is active as this +* would disable PER wakeups completely +*/ + if (per_state == PWRDM_POWER_OFF + new_core_state PWRDM_POWER_RET) + per_state = PWRDM_POWER_RET; + + } else if (saved_per_state == PWRDM_POWER_OFF) + per_state = PWRDM_POWER_RET; + + /* +* If we are attempting CORE off, check if any other +* powerdomains are at retention or higher. CORE off causes +* chipwide reset which would reset these domains also. +*/ + if (new_core_state == PWRDM_POWER_OFF) { + dss_state = pwrdm_get_idle_state(dss_pd); + iva2_state = pwrdm_get_idle_state(iva2_pd); + sgx_state = pwrdm_get_idle_state(sgx_pd); + usb_state
[PATCH] Smartreflex: Avoid unnecessary spam
From: Tero Kristo tero.kri...@nokia.com Current warning messages will be constantly printed out during normal operation if smartreflex autocompensation is disabled. Signed-off-by: Tero Kristo tero.kri...@nokia.com --- arch/arm/mach-omap2/smartreflex.c | 10 +- 1 files changed, 1 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index be3a1da..db228b2 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -675,13 +675,8 @@ void sr_start_vddautocomap(int srid, u32 target_opp_no) sr_configure(sr); } - if (sr-is_autocomp_active == 1) - pr_warning(SR%d: VDD autocomp is already active\n, - srid); - sr-is_autocomp_active = 1; if (!sr_enable(sr, target_opp_no)) { - pr_warning(SR%d: VDD autocomp not activated\n, srid); sr-is_autocomp_active = 0; if (sr-is_sr_reset == 1) sr_clk_disable(sr); @@ -707,11 +702,8 @@ int sr_stop_vddautocomap(int srid) /* Reset the volatage for current OPP */ sr_reset_voltage(srid); return true; - } else { - pr_warning(SR%d: VDD autocomp is not active\n, - srid); + } else return false; - } } EXPORT_SYMBOL(sr_stop_vddautocomap); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] PM: Fix a bug with noncore dpll rate calculation
Noncore dpll can enter autoidle state, in which case the rate calculation fails. Fixed by checking dpll mode instead of idle status. Signed-off-by: Tero Kristo [EMAIL PROTECTED] --- arch/arm/mach-omap2/clock.c | 16 +++- arch/arm/mach-omap2/cm-regbits-34xx.h |2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 522ce6f..bbd3e82 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -212,9 +212,16 @@ u32 omap2_get_dpll_rate(struct clk *clk) return 0; /* Return bypass rate if DPLL is bypassed */ - v = cm_read_mod_reg(clk-prcm_mod, dd-idlest_reg); - v = dd-idlest_mask; - v = __ffs(dd-idlest_mask); + if (cpu_is_omap34xx()) { + v = cm_read_mod_reg(clk-prcm_mod, dd-control_reg); + v = dd-enable_mask; + v = __ffs(dd-enable_mask); + } else { + v = cm_read_mod_reg(clk-prcm_mod, dd-idlest_reg); + v = dd-idlest_mask; + v = __ffs(dd-idlest_mask); + } + if (cpu_is_omap24xx()) { if (v == ST_CORE_CLK_REF) @@ -224,9 +231,8 @@ u32 omap2_get_dpll_rate(struct clk *clk) } else if (cpu_is_omap34xx()) { - if (!v) + if (v == OMAP3430_EN_MPU_DPLL_BYPASS) return dd-bypass_clk-rate; - } v = cm_read_mod_reg(clk-prcm_mod, dd-mult_div1_reg); diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h index 6f3f5a3..9995353 100644 --- a/arch/arm/mach-omap2/cm-regbits-34xx.h +++ b/arch/arm/mach-omap2/cm-regbits-34xx.h @@ -112,6 +112,8 @@ #define OMAP3430_EN_MPU_DPLL_DRIFTGUARD_MASK (1 3) #define OMAP3430_EN_MPU_DPLL_SHIFT 0 #define OMAP3430_EN_MPU_DPLL_MASK (0x7 0) +#define OMAP3430_EN_MPU_DPLL_LOCK (0x7 0) +#define OMAP3430_EN_MPU_DPLL_BYPASS(0x5 0) /* CM_IDLEST_MPU */ #define OMAP3430_ST_MPU(1 0) -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] PM: Added three PLL registers to the PRCM context save
These registers are now also saved: CM_CLKSEL4 CM_CLKEN CM_CLKEN2 Signed-off-by: Tero Kristo [EMAIL PROTECTED] --- arch/arm/mach-omap2/prcm.c | 14 ++ 1 files changed, 14 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index d5a1e4b..c64b668 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -46,7 +46,10 @@ struct omap3_prcm_regs { u32 emu_cm_clksel; u32 emu_cm_clkstctrl; u32 pll_cm_autoidle2; + u32 pll_cm_clksel4; u32 pll_cm_clksel5; + u32 pll_cm_clken; + u32 pll_cm_clken2; u32 cm_polctrl; u32 iva2_cm_fclken; u32 core_cm_fclken1; @@ -233,8 +236,14 @@ void omap3_prcm_save_context(void) cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSTCTRL); prcm_context.pll_cm_autoidle2 = cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); + prcm_context.pll_cm_clksel4 = + cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4); prcm_context.pll_cm_clksel5 = cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5); + prcm_context.pll_cm_clken = + cm_read_mod_reg(PLL_MOD, CM_CLKEN); + prcm_context.pll_cm_clken2 = + cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2); prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL); prcm_context.iva2_cm_fclken = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_FCLKEN); @@ -380,8 +389,13 @@ void omap3_prcm_restore_context(void) CM_CLKSTCTRL); cm_write_mod_reg(prcm_context.pll_cm_autoidle2, PLL_MOD, CM_AUTOIDLE2); + cm_write_mod_reg(prcm_context.pll_cm_clksel4, PLL_MOD, + OMAP3430ES2_CM_CLKSEL4); cm_write_mod_reg(prcm_context.pll_cm_clksel5, PLL_MOD, OMAP3430ES2_CM_CLKSEL5); + cm_write_mod_reg(prcm_context.pll_cm_clken, PLL_MOD, CM_CLKEN); + cm_write_mod_reg(prcm_context.pll_cm_clken2, PLL_MOD, + OMAP3430ES2_CM_CLKEN2); __raw_writel(prcm_context.cm_polctrl, OMAP3430_CM_POLCTRL); cm_write_mod_reg(prcm_context.iva2_cm_fclken, OMAP3430_IVA2_MOD, CM_FCLKEN); -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] OMAP3: Fixes for suspend / resume GPIO wake-up handling
Signed-off-by: Tero Kristo [EMAIL PROTECTED] --- arch/arm/plat-omap/gpio.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index f4ec3af..62349fd 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -1585,7 +1585,7 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) #endif #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) case METHOD_GPIO_24XX: - wake_status = bank-base + OMAP24XX_GPIO_SETWKUENA; + wake_status = bank-base + OMAP24XX_GPIO_WAKE_EN; wake_clear = bank-base + OMAP24XX_GPIO_CLEARWKUENA; wake_set = bank-base + OMAP24XX_GPIO_SETWKUENA; break; @@ -1608,7 +1608,7 @@ static int omap_gpio_resume(struct sys_device *dev) { int i; - if (!cpu_is_omap24xx() !cpu_is_omap16xx()) + if (!cpu_class_is_omap2() !cpu_is_omap16xx()) return 0; for (i = 0; i gpio_bank_count; i++) { -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] PM: Added suspend target state control to debugfs for OMAP3
Target state can be read / programmed via files under: [debugfs]/pm_debug/[pwrdm]/suspend Signed-off-by: Tero Kristo [EMAIL PROTECTED] --- arch/arm/mach-omap2/pm-debug.c | 30 -- arch/arm/mach-omap2/pm.h |4 arch/arm/mach-omap2/pm34xx.c | 24 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 82219f4..ac61d15 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -26,6 +26,7 @@ #include linux/clk.h #include linux/err.h #include linux/io.h +#include linux/module.h #include mach/clock.h #include mach/board.h @@ -511,11 +512,28 @@ int pm_dbg_regset_init(int reg_set) return 0; } -static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) +static int pwrdm_suspend_get(void *data, u64 *val) +{ + *val = omap3_pm_get_suspend_state((struct powerdomain *)data); + + if (*val = 0) + return 0; + return *val; +} + +static int pwrdm_suspend_set(void *data, u64 val) +{ + return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val); +} + +DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, pwrdm_suspend_set, %llu\n); + +static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) { int i; s64 t; struct timespec now; + struct dentry *d; getnstimeofday(now); t = timespec_to_ns(now); @@ -525,6 +543,14 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) pwrdm-timer = t; + if (strncmp(pwrdm-name, dpll, 4) == 0) + return 0; + + d = debugfs_create_dir(pwrdm-name, (struct dentry *)dir); + + (void) debugfs_create_file(suspend, S_IRUGO|S_IWUSR, d, + (void *)pwrdm, pwrdm_suspend_fops); + return 0; } @@ -545,7 +571,7 @@ static int __init pm_dbg_init(void) (void) debugfs_create_file(time, S_IRUGO, d, (void *)DEBUG_FILE_TIMERS, debug_fops); - pwrdm_for_each(pwrdms_setup, NULL); + pwrdm_for_each(pwrdms_setup, (void *)d); pm_dbg_dir = debugfs_create_dir(registers, d); if (IS_ERR(pm_dbg_dir)) diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 4b1ba7c..78fde57 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -34,8 +34,12 @@ extern void omap2_block_sleep(void); extern void omap2_allow_sleep(void); #ifdef CONFIG_ARCH_OMAP3 extern void omap3_pm_off_mode_enable(int); +extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); +extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); #else #define omap3_pm_off_mode_enable(int) do {} while (0); +#define omap3_pm_get_suspend_state(pwrdm) do {} while (0); +#define omap3_pm_set_suspend_state(pwrdm,state) do {} while (0); #endif extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 191299c..73ac22c 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -780,6 +780,30 @@ void omap3_pm_off_mode_enable(int enable) } } +int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) +{ + struct power_state *pwrst; + + list_for_each_entry(pwrst, pwrst_list, node) { + if (pwrst-pwrdm == pwrdm) + return pwrst-next_state; + } + return -EINVAL; +} + +int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) +{ + struct power_state *pwrst; + + list_for_each_entry(pwrst, pwrst_list, node) { + if (pwrst-pwrdm == pwrdm) { + pwrst-next_state = state; + return 0; + } + } + return -EINVAL; +} + static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) { struct power_state *pwrst; -- 1.5.4.3 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html