[PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states
Hi This series converts the OMAP2+ powerdomain and PM code to use "functional power states" - high-level power states such as "OSWR", which reflect changes in multiple underlying registers, rather than expecting high-level PM code to program the registers directly. This is intended to reduce the complexity of the high-level PM code and to make it easier to implement register caching of the various powerdomain registers, some of which are quite slow to access. - Paul --- vmlinux object size (delta in bytes from TEST_pm_cleanup_fixes_b_3.9 (2f8d7b1f0048df431ca226d81c5c27c4dd21953b)): text data bsstotal kernel +456 -560 +400 am33xx_only +448 -960 +352 n800_multi_omap2xxx +448 -960 +352 n800_only_a 0000 omap1_defconfig 0000 omap1_defconfig_1510innovator_only 0000 omap1_defconfig_5912osk_only +1180 -7440 +436 omap2plus_defconfig +584 -720 +512 omap2plus_defconfig_2430sdp_only +1244 -8080 +436 omap2plus_defconfig_cpupm +976-12240 -248 omap2plus_defconfig_no_pm +844 -4080 +436 omap2plus_defconfig_omap2_4_only +1088 -6240 +464 omap2plus_defconfig_omap3_4_only +1292-1232 -352 -292 rmk_omap3430_ldp_allnoconfig +916 -7200 +196 rmk_omap3430_ldp_oldconfig +1292-1232 -352 -292 rmk_omap4430_sdp_allnoconfig +840 -3920 +448 rmk_omap4430_sdp_oldconfig Boot-time memory difference (delta in bytes from TEST_pm_cleanup_fixes_b_3.9 (2f8d7b1f0048df431ca226d81c5c27c4dd21953b)) avail rsrvd high freed board kconfig -8k 8k . . 2430sdpomap2plus_defconfig -8k 8k . . 3517evmomap2plus_defconfig -8k 8k . . 3530es3beagle omap2plus_defconfig -8k 8k . . 3730beaglexm omap2plus_defconfig -8k 8k . . 37xxevmomap2plus_defconfig -8k 8k . . 4430es2panda omap2plus_defconfig -8k 8k . . 4460pandaesomap2plus_defconfig -8k 8k . . cmt3517omap2plus_defconfig Jean Pihet (6): ARM: OMAP2+: PM: introduce power domains functional states ARM: OMAP2+: PM debug: trace the functional power domains states ARM: OMAP2xxx: PM: convert to use the functional power states API ARM: OMAP3xxx: PM: convert to use the functional power states API ARM: OMAP44xx: PM: convert to use the functional power states API ARM: OMAP2+: PM: use power domain functional state in stats counters Paul Walmsley (6): ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs ARM: OMAP2+: powerdomain: add ability to test for supported power states ARM: OMAP2+: powerdomain/PM: only program supported power states ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain arch/arm/mach-omap2/common.h |7 arch/arm/mach-omap2/cpuidle34xx.c | 95 +- arch/arm/mach-omap2/cpuidle44xx.c | 32 - arch/arm/mach-omap2/omap-hotplug.c|2 arch/arm/mach-omap2/omap-mpuss-lowpower.c | 69 +- arch/arm/mach-omap2/pm-debug.c| 46 - arch/arm/mach-omap2/pm.h |2 arch/arm/mach-omap2/pm24xx.c | 33 - arch/arm/mach-omap2/pm34xx.c | 188 +++- arch/arm/mach-omap2/pm44xx.c | 47 + arch/arm/mach-omap2/powerdomain.c | 1235 + arch/arm/mach-omap2/powerdomain.h | 69 +- 12 files changed, 1040 insertions(+), 785 deletions(-) -- 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 01/12] ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities
Add several functions to report on whether powerdomains can change their power state or logic retention power state, and whether those abilities can be controlled by the kernel. This code is used in subsequent patches that add the functional power state code. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 56 + 1 file changed, 56 insertions(+) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 2a5f15b..94b89a25 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -203,6 +203,62 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) return 0; } +/** + * _pwrdm_pwrst_is_controllable - can software change the powerdomain pwrst? + * @pwrdm: struct powerdomain * to test + * + * If the kernel can program the power state that the powerdomain + * @pwrdm should enter next, return 1; otherwise, return 0. + */ +static bool _pwrdm_pwrst_is_controllable(struct powerdomain *pwrdm) +{ + return (!pwrdm->pwrsts || pwrdm->pwrsts == PWRSTS_ON) ? 0 : 1; +} + +/** + * _pwrdm_pwrst_can_change - can the power state of @pwrdm change? + * @pwrdm: struct powerdomain * to test + * + * If the power state of the powerdomain represented by @pwrdm can + * change (i.e., is not always on), and the kernel has some way to + * detect this, return 1; otherwise, return 0. XXX The current + * implementation of this is based on an assumption and has not been + * verified against all OMAPs. + */ +static bool _pwrdm_pwrst_can_change(struct powerdomain *pwrdm) +{ + return _pwrdm_pwrst_is_controllable(pwrdm); +} + +/** + * _pwrdm_logic_retst_is_controllable - can software change the logic retst? + * @pwrdm: struct powerdomain * to test + * + * If the kernel can program the power state that the powerdomain + * @pwrdm logic should enter when the @pwrdm enters the RETENTION + * power state, return 1; otherwise, return 0. + */ +static bool _pwrdm_logic_retst_is_controllable(struct powerdomain *pwrdm) +{ + return (!pwrdm->pwrsts_logic_ret || + pwrdm->pwrsts_logic_ret == PWRSTS_RET) ? 0 : 1; +} + +/** + * _pwrdm_logic_retst_can_change - can the logic retst change on @pwrdm? + * @pwrdm: struct powerdomain * to test + * + * If the logic powerstate for the powerdomain represented by @pwrdm + * can ever be something other than the powerdomain's powerstate, and + * the kernel has some way to detect this, return 1; otherwise, return + * 0. XXX The current implementation of this is based on an + * assumption and has not been verified against all OMAPs. + */ +static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) +{ + return _pwrdm_logic_retst_is_controllable(pwrdm); +} + /* Public functions */ /** -- 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/12] ARM: OMAP2+: PM debug: trace the functional power domains states
From: Jean Pihet Trace the power domain transitions using the functional power states, which include the power and logic states. Signed-off-by: Jean Pihet [p...@pwsan.com: split the fix that was originally part of this patch into a separate patch] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 14 -- 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 18f33de..2c732b6 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -881,13 +881,8 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) pr_debug("powerdomain: %s: setting next powerstate to %0x\n", pwrdm->name, pwrst); - if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) { - /* Trace the pwrdm desired target state */ - trace_power_domain_target(pwrdm->name, pwrst, - smp_processor_id()); - /* Program the pwrdm desired target state */ + if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst); - } return ret; } @@ -1571,6 +1566,9 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst) pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst, pwrdm->name); + /* Trace the pwrdm desired target state */ + trace_power_domain_target(pwrdm->name, fpwrst, smp_processor_id()); + pwrdm_lock(pwrdm); ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst); pwrdm_unlock(pwrdm); @@ -1658,6 +1656,10 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst) if (next_fpwrst == fpwrst) goto psf_out; + /* Trace the pwrdm desired target state */ + trace_power_domain_target(pwrdm->name, next_fpwrst, + smp_processor_id()); + sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, pwrst, &hwsup); -- 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/12] ARM: OMAP3xxx: PM: convert to use the functional power states API
From: Jean Pihet Use the functional power states as the API to control power domains: - use the PWRDM_FUNC_PWRST_* macros for the power states and logic settings, - the function pwrdm_set_next_fpwrst(), which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst() to program the power domains next states, - the function pwrdm_set_fpwrst(), which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state(). Signed-off-by: Jean Pihet [p...@pwsan.com: split the original patch into OMAP2/3/4 variants; clean up omap3_save_secure_ram_context(); fix commit message; warn if sets fail; various other changes] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cpuidle34xx.c | 95 --- arch/arm/mach-omap2/pm.h |2 arch/arm/mach-omap2/pm34xx.c | 156 +++-- 3 files changed, 130 insertions(+), 123 deletions(-) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index e6215b5..a8e6263 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -36,9 +36,9 @@ /* Mach specific information to be recorded in the C-state driver_data */ struct omap3_idle_statedata { - u8 mpu_state; - u8 core_state; - u8 per_min_state; + u8 mpu_fpwrst; + u8 core_fpwrst; + u8 per_min_fpwrst; u8 flags; }; @@ -61,41 +61,41 @@ static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; */ static struct omap3_idle_statedata omap3_idle_data[] = { { - .mpu_state = PWRDM_POWER_ON, - .core_state = PWRDM_POWER_ON, + .mpu_fpwrst = PWRDM_FUNC_PWRST_ON, + .core_fpwrst = PWRDM_FUNC_PWRST_ON, /* In C1 do not allow PER state lower than CORE state */ - .per_min_state = PWRDM_POWER_ON, + .per_min_fpwrst = PWRDM_FUNC_PWRST_ON, .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE, }, { - .mpu_state = PWRDM_POWER_ON, - .core_state = PWRDM_POWER_ON, - .per_min_state = PWRDM_POWER_RET, + .mpu_fpwrst = PWRDM_FUNC_PWRST_ON, + .core_fpwrst = PWRDM_FUNC_PWRST_ON, + .per_min_fpwrst = PWRDM_FUNC_PWRST_CSWR, }, { - .mpu_state = PWRDM_POWER_RET, - .core_state = PWRDM_POWER_ON, - .per_min_state = PWRDM_POWER_RET, + .mpu_fpwrst = PWRDM_FUNC_PWRST_CSWR, + .core_fpwrst = PWRDM_FUNC_PWRST_ON, + .per_min_fpwrst = PWRDM_FUNC_PWRST_CSWR, }, { - .mpu_state = PWRDM_POWER_OFF, - .core_state = PWRDM_POWER_ON, - .per_min_state = PWRDM_POWER_RET, + .mpu_fpwrst = PWRDM_FUNC_PWRST_OFF, + .core_fpwrst = PWRDM_FUNC_PWRST_ON, + .per_min_fpwrst = PWRDM_FUNC_PWRST_CSWR, }, { - .mpu_state = PWRDM_POWER_RET, - .core_state = PWRDM_POWER_RET, - .per_min_state = PWRDM_POWER_OFF, + .mpu_fpwrst = PWRDM_FUNC_PWRST_CSWR, + .core_fpwrst = PWRDM_FUNC_PWRST_CSWR, + .per_min_fpwrst = PWRDM_FUNC_PWRST_OFF, }, { - .mpu_state = PWRDM_POWER_OFF, - .core_state = PWRDM_POWER_RET, - .per_min_state = PWRDM_POWER_OFF, + .mpu_fpwrst = PWRDM_FUNC_PWRST_OFF, + .core_fpwrst = PWRDM_FUNC_PWRST_CSWR, + .per_min_fpwrst = PWRDM_FUNC_PWRST_OFF, }, { - .mpu_state = PWRDM_POWER_OFF, - .core_state = PWRDM_POWER_OFF, - .per_min_state = PWRDM_POWER_OFF, + .mpu_fpwrst = PWRDM_FUNC_PWRST_OFF, + .core_fpwrst = PWRDM_FUNC_PWRST_OFF, + .per_min_fpwrst = PWRDM_FUNC_PWRST_OFF, }, }; @@ -116,15 +116,15 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) { clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); } else { - pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state); - pwrdm_set_next_pwrst(core_pd, cx->core_state); + pwrdm_set_next_fpwrst(mpu_pd, cx->mpu_fpwrst); + pwrdm_set_next_fpwrst(core_pd, cx->core_fpwrst); } /* * Call idle CPU PM enter notifier chain so that * VFP context is saved. */ - if (cx->mpu_state == PWRDM_POWER_OFF) + if (cx->mpu_fpwrst == PWRDM_FUNC_PWRST_OFF) cpu_pm_enter(); /* Execute ARM wfi */ @@ -134,8 +134,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, * Call idle CPU PM enter notifier chain to restore * VFP context. */ - if (cx->mpu_state == PWRDM_POWER_
[PATCH 06/12] ARM: OMAP44xx: PM: convert to use the functional power states API
From: Jean Pihet Use the functional power states as the API to control power domains: - use the PWRDM_FUNC_PWRST_* and PWRDM_LOGIC_MEM_PWRST_* macros for the power states and logic settings, - the function pwrdm_set_next_fpwrst, which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst to program the power domains next states, - the function pwrdm_set_fpwrst, which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state. Signed-off-by: Jean Pihet [p...@pwsan.com: split the original patch into OMAP2/3/4 variants; warn if sets fail; various other changes] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/common.h |7 +-- arch/arm/mach-omap2/cpuidle44xx.c | 32 + arch/arm/mach-omap2/omap-hotplug.c|2 - arch/arm/mach-omap2/omap-mpuss-lowpower.c | 69 + arch/arm/mach-omap2/pm44xx.c | 42 +- 5 files changed, 79 insertions(+), 73 deletions(-) diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index c57eeea..5ad846a 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -235,14 +235,13 @@ extern void omap5_secondary_startup(void); #if defined(CONFIG_SMP) && defined(CONFIG_PM) extern int omap4_mpuss_init(void); -extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); +extern int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst); extern int omap4_finish_suspend(unsigned long cpu_state); extern void omap4_cpu_resume(void); -extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); +extern int omap4_mpuss_hotplug_cpu(unsigned int cpu, u8 fpwrst); extern u32 omap4_mpuss_read_prev_context_state(void); #else -static inline int omap4_enter_lowpower(unsigned int cpu, - unsigned int power_state) +static inline int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst) { cpu_do_idle(); return 0; diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index d639aef..2cb5332 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -25,26 +25,22 @@ /* Machine specific information */ struct omap4_idle_statedata { - u32 cpu_state; - u32 mpu_logic_state; - u32 mpu_state; + u8 cpu_pwrst; + u8 mpu_pwrst; }; static struct omap4_idle_statedata omap4_idle_data[] = { { - .cpu_state = PWRDM_POWER_ON, - .mpu_state = PWRDM_POWER_ON, - .mpu_logic_state = PWRDM_POWER_RET, + .cpu_pwrst = PWRDM_FUNC_PWRST_ON, + .mpu_pwrst = PWRDM_FUNC_PWRST_ON, }, { - .cpu_state = PWRDM_POWER_OFF, - .mpu_state = PWRDM_POWER_RET, - .mpu_logic_state = PWRDM_POWER_RET, + .cpu_pwrst = PWRDM_FUNC_PWRST_OFF, + .mpu_pwrst = PWRDM_FUNC_PWRST_CSWR, }, { - .cpu_state = PWRDM_POWER_OFF, - .mpu_state = PWRDM_POWER_RET, - .mpu_logic_state = PWRDM_POWER_OFF, + .cpu_pwrst = PWRDM_FUNC_PWRST_OFF, + .mpu_pwrst = PWRDM_FUNC_PWRST_OSWR, }, }; @@ -93,7 +89,7 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, * out of coherency and in OFF mode. */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { - while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) { + while (pwrdm_read_fpwrst(cpu_pd[1]) != PWRDM_FUNC_PWRST_OFF) { cpu_relax(); /* @@ -118,19 +114,17 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, cpu_pm_enter(); if (dev->cpu == 0) { - pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); - omap_set_pwrdm_state(mpu_pd, cx->mpu_state); + WARN_ON(pwrdm_set_fpwrst(mpu_pd, cx->mpu_pwrst)); /* * Call idle CPU cluster PM enter notifier chain * to save GIC and wakeupgen context. */ - if ((cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) - cpu_cluster_pm_enter(); + if (cx->mpu_pwrst == PWRDM_FUNC_PWRST_OSWR) + cpu_cluster_pm_enter(); } - omap4_enter_lowpower(dev->cpu, cx->cpu_state); + omap4_mpuss_enter_lowpower(dev->cpu, cx->cpu_pwrst); cpu_done[dev->cpu] = true; /* Wakeup CPU1 only if it is not offlined */ diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c index e712d17..d38b12d 100644 --- a/arch/arm/mach-omap2/omap-hotplug.c +++ b/arch/arm/mach-omap2/omap-hotplug.c @@ -53,7 +
[PATCH 12/12] ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain
Assume that the memory bank power states follow the powerdomain power states. The motivations are to reduce the amount of powerdomain code, decrease the execution time of the powerdomain state switch code, and simplify the power state debug. This assumption is true for the currently-implemented functional power states. If it ceases to be true, the memory bank power states should be controlled via the functional power states, rather than controlled via low-level functions. For the moment, the underlying implementation code in mach-omap2/prm*.c has been preserved, although some of that code may be removable too. Signed-off-by: Paul Walmsley Cc: Tero Kristo Cc: Rajendra Nayak Cc: Kevin Hilman --- arch/arm/mach-omap2/pm-debug.c|4 - arch/arm/mach-omap2/pm24xx.c |9 - arch/arm/mach-omap2/powerdomain.c | 277 +++-- arch/arm/mach-omap2/powerdomain.h |9 - 4 files changed, 79 insertions(+), 220 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 72cf9e0..03da2e3 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -108,10 +108,6 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i), pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]); - for (i = 0; i < pwrdm->banks; i++) - seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, - pwrdm->ret_mem_off_counter[i]); - seq_printf(s, "\n"); return 0; diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 29abb63..99c16c2 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -230,7 +230,6 @@ out: static void __init prcm_setup_regs(void) { - int i, num_mem_banks; struct powerdomain *pwrdm; /* @@ -240,14 +239,6 @@ static void __init prcm_setup_regs(void) omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD, OMAP2_PRCM_SYSCONFIG_OFFSET); - /* -* Set CORE powerdomain memory banks to retain their contents -* during RETENTION -*/ - num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm); - for (i = 0; i < num_mem_banks; i++) - pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); - /* Force-power down DSP, GFX powerdomains */ pwrdm = clkdm_get_pwrdm(dsp_clkdm); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index a70e3f6..7a32fcc 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -118,9 +118,6 @@ static int _pwrdm_register(struct powerdomain *pwrdm) for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++) pwrdm->fpwrst_counter[i] = 0; - for (i = 0; i < pwrdm->banks; i++) - pwrdm->ret_mem_off_counter[i] = 0; - arch_pwrdm->pwrdm_wait_transition(pwrdm); pwrdm->fpwrst = pwrdm_read_fpwrst(pwrdm); pwrdm->fpwrst_counter[pwrdm->fpwrst - PWRDM_FPWRST_OFFSET] = 1; @@ -364,7 +361,6 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm) if (next_logic < 0) return next_logic; } - ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst); return (ret) ? ret : fpwrst; @@ -437,12 +433,86 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) return (ret) ? ret : fpwrst; } +/** + * _pwrdm_set_mem_onst - set memory power state while powerdomain ON + * @pwrdm: struct powerdomain * to set + * @bank: memory bank number to set (0-3) + * @pwrst: one of the PWRDM_POWER_* macros + * + * Set the next power state @pwrst that memory bank @bank of the + * powerdomain @pwrdm will enter when the powerdomain enters the ON + * state. @bank will be a number from 0 to 3, and represents different + * types of memory, depending on the powerdomain. Returns -EINVAL if + * the powerdomain pointer is null or the target power state is not + * not supported for this memory bank, -EEXIST if the target memory + * bank does not exist or is not controllable, or returns 0 upon + * success. + */ +static int _pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) +{ + int ret = -EINVAL; + + if (!pwrdm) + return -EINVAL; + + if (pwrdm->banks < (bank + 1)) + return -EEXIST; + + if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst))) + return -EINVAL; + + pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n", +pwrdm->name, bank, pwrst); + + if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst) + ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst); + + return ret; +} + +/** + * _pwrdm_set_mem_retst - set memory power state while powerdoma
[PATCH 09/12] ARM: OMAP2+: powerdomain: add ability to test for supported power states
Add pwrdm_supports_fpwrst(), intended for use by the PM code to avoid attempting to program a powerdomain to a power state that it doesn't support. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 33 + arch/arm/mach-omap2/powerdomain.h |1 + 2 files changed, 34 insertions(+) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 86fe84c..6ba79df 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1495,3 +1495,36 @@ int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) return ret; } +/** + * pwrdm_supports_fpwrst - does the powerdomain @pwrdm support the @fpwrst power + * state? + * @pwrdm: struct powerdomain * pointing to a powerdomain to test + * @fpwrst: functional power state + * + * Returns true if the powerdomain pointed to by @pwrdm can enter the + * functional power state @fpwrst, or false if not. + */ +bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst) +{ + u8 pwrst, logic; + int ret; + + if (!pwrdm || IS_ERR(pwrdm)) + return false; + + ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic); + if (ret) + return false; + + pr_debug("%s: pwrdm %s: set fpwrst %0x\n", __func__, pwrdm->name, +fpwrst); + + if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET && + !(pwrdm->pwrsts_logic_ret & (1 << logic))) + return false; + + if (!(pwrdm->pwrsts & (1 << pwrst))) + return false; + + return true; +} diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index aa1c9ae..52be8cd 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -260,6 +260,7 @@ extern int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst); extern int pwrdm_read_fpwrst(struct powerdomain *pwrdm); extern int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm); +extern bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst); extern void omap242x_powerdomains_init(void); extern void omap243x_powerdomains_init(void); -- 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 11/12] ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init
During powerdomain init, we were previously programming a reasonable default for the powerdomain and logic next-power-state fields, but not touching the memory bank next-power-state fields. To ensure that the previous OS or bootloader didn't leave the system in a bad state, program the memory bank next-power-state bitfields to reasonable defaults. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 21 ++--- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index fdeabbf..a70e3f6 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -563,21 +563,28 @@ int pwrdm_register_pwrdms(struct powerdomain **ps) * * Do whatever is necessary to initialize registered powerdomains and * powerdomain code. Currently, this programs the next power state - * for each powerdomain to ON. This prevents powerdomains from - * unexpectedly losing context or entering high wakeup latency modes - * with non-power-management-enabled kernels. Must be called after - * pwrdm_register_pwrdms(). Returns -EACCES if called before - * pwrdm_register_pwrdms(), or 0 upon success. + * for each powerdomain to ON, and programs the memory bank power + * states to follow the powerdomain power states. This prevents + * powerdomains from unexpectedly losing context or entering high + * wakeup latency modes with non-power-management-enabled kernels. + * Must be called after pwrdm_register_pwrdms(). Returns -EACCES if + * called before pwrdm_register_pwrdms(), or 0 upon success. */ int pwrdm_complete_init(void) { struct powerdomain *temp_p; + int i; if (list_empty(&pwrdm_list)) return -EACCES; - list_for_each_entry(temp_p, &pwrdm_list, node) - pwrdm_set_next_fpwrst(temp_p, PWRDM_FUNC_PWRST_ON); + list_for_each_entry(temp_p, &pwrdm_list, node) { + for (i = 0; i < temp_p->banks; i++) { + pwrdm_set_mem_onst(temp_p, i, PWRDM_POWER_ON); + pwrdm_set_mem_retst(temp_p, i, PWRDM_POWER_RET); + } + WARN_ON(pwrdm_set_next_fpwrst(temp_p, PWRDM_FUNC_PWRST_ON)); + } return 0; } -- 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/12] ARM: OMAP2+: powerdomain/PM: only program supported power states
Previously the PM code attempted to program power states that the underlying powerdomain didn't support. Change this to only program power states that are supported by the hardware. In the future, the PM code should be changed further to program explicit lists of powerdomain power states that are valid for each chip (and supported by the underlying software). Also the powerdomain code should return errors when PM code tries to program an unsupported power state, rather than simply ignoring the requrest. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/pm34xx.c | 34 + arch/arm/mach-omap2/pm44xx.c |9 - arch/arm/mach-omap2/powerdomain.c | 74 ++--- 3 files changed, 52 insertions(+), 65 deletions(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 8aac26e..c4d4154 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -395,7 +395,14 @@ restore: /* Restore next_pwrsts */ list_for_each_entry(pwrst, &pwrst_list, node) { prev_fpwrst = pwrdm_read_prev_fpwrst(pwrst->pwrdm); - if (prev_fpwrst > pwrst->next_fpwrst) { + /* +* The SGX powerdomain will report its previous state as +* INACTIVE when it's been programmed to ON. This seems to +* be the only OMAP3 powerdomain that does this. +*/ + if (prev_fpwrst == PWRDM_FUNC_PWRST_INACTIVE) + prev_fpwrst = PWRDM_FUNC_PWRST_ON; + if (prev_fpwrst != pwrst->next_fpwrst) { pr_info("Powerdomain %s didn't enter target state %s - entered state %s instead\n", pwrst->pwrdm->name, pwrdm_convert_fpwrst_to_name(pwrst->next_fpwrst), @@ -575,6 +582,10 @@ void omap3_pm_off_mode_enable(int enable) fpwrst = (enable) ? PWRDM_FUNC_PWRST_OFF : PWRDM_FUNC_PWRST_CSWR; + /* +* XXX This should be replaced by explicit lists of +* powerdomains with specific powerstates to set +*/ list_for_each_entry(pwrst, &pwrst_list, node) { if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) && pwrst->pwrdm == core_pwrdm && @@ -584,6 +595,12 @@ void omap3_pm_off_mode_enable(int enable) __func__); } else { pwrst->next_fpwrst = fpwrst; + if (!pwrdm_supports_fpwrst(pwrst->pwrdm, + pwrst->next_fpwrst)) + pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR; + if (!pwrdm_supports_fpwrst(pwrst->pwrdm, + pwrst->next_fpwrst)) + pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON; } WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst)); } @@ -603,9 +620,17 @@ int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, u8 fpwrst) { struct power_state *pwrst; + /* +* XXX This should be replaced by per-powerdomain suspend +* power state files +*/ list_for_each_entry(pwrst, &pwrst_list, node) { if (pwrst->pwrdm == pwrdm) { pwrst->next_fpwrst = fpwrst; + if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst)) + pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR; + if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst)) + pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON; return 0; } } @@ -623,7 +648,14 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) if (!pwrst) return -ENOMEM; pwrst->pwrdm = pwrdm; + + /* +* XXX This should be replaced by explicit lists of +* powerdomains with specific powerstates to set +*/ pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR; + if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst)) + pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON; list_add(&pwrst->node, &pwrst_list); if (pwrdm_has_hdwr_sar(pwrdm)) diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 595f84e..5db9a91 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -67,8 +67,7 @@ static int omap4_pm_suspend(void) /* Restore next powerdomain state */ list_for_each_entry(pwrst, &pwrst_list, node) { prev_fpwrst = pwrdm_read_prev_fpwrst(pwrst->pwrdm); - /* XXX test below should be != */ - if (prev_fpwrst > pwrst->next_fpwrst) { + if (prev_fpwrst != pwrst->next_fpwrst) {
[PATCH 08/12] ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs
The powerdomain code that exported the ability to read or change the previous, current, or next powerdomain or logic power states can now be removed. All this is controlled via the powerdomain functional power state interface now. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 270 +++-- arch/arm/mach-omap2/powerdomain.h |9 - 2 files changed, 21 insertions(+), 258 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 3e2e263..86fe84c 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -253,9 +253,6 @@ static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max) static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst, u8 *pwrdm_pwrst, u8 *logic_retst) { - if (!pwrdm || !pwrdm_pwrst || !logic_retst) - return -EINVAL; - switch (fpwrst) { case PWRDM_FUNC_PWRST_ON: *pwrdm_pwrst = PWRDM_POWER_ON; @@ -317,9 +314,6 @@ static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst, static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic, u8 *fpwrst) { - if (!pwrdm || !fpwrst) - return -EINVAL; - switch (pwrst) { case PWRDM_POWER_ON: *fpwrst = PWRDM_FUNC_PWRST_ON; @@ -370,16 +364,27 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm, if (!_pwrdm_pwrst_is_controllable(pwrdm)) return 0; + if (!arch_pwrdm || !arch_pwrdm->pwrdm_set_next_pwrst) + return -EINVAL; + + if (!(pwrdm->pwrsts & (1 << pwrst))) + return -EINVAL; + if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET) { - ret = pwrdm_set_logic_retst(pwrdm, logic); - if (ret) { - pr_err("%s: unable to set logic state %0x of powerdomain: %s\n", - __func__, logic, pwrdm->name); - return ret; + if (!(pwrdm->pwrsts_logic_ret & (1 << logic))) + return -EINVAL; + + if (arch_pwrdm->pwrdm_set_logic_retst) { + ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic); + if (ret) { + pr_err("%s: unable to set logic state %0x of powerdomain: %s\n", + __func__, logic, pwrdm->name); + return ret; + } } } - ret = pwrdm_set_next_pwrst(pwrdm, pwrst); + ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst); if (ret) pr_err("%s: unable to set power state %0x of powerdomain: %s\n", __func__, pwrst, pwrdm->name); @@ -847,133 +852,6 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) } /** - * pwrdm_set_next_pwrst - set next powerdomain power state - * @pwrdm: struct powerdomain * to set - * @pwrst: one of the PWRDM_POWER_* macros - * - * Set the powerdomain @pwrdm's next power state to @pwrst. The powerdomain - * may not enter this state immediately if the preconditions for this state - * have not been satisfied. Returns -EINVAL if the powerdomain pointer is - * null or if the power state is invalid for the powerdomin, or returns 0 - * upon success. - */ -int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) -{ - int ret = -EINVAL; - - if (!pwrdm) - return -EINVAL; - - if (!(pwrdm->pwrsts & (1 << pwrst))) - return -EINVAL; - - pr_debug("powerdomain: %s: setting next powerstate to %0x\n", -pwrdm->name, pwrst); - - if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) - ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst); - - return ret; -} - -/** - * pwrdm_read_next_pwrst - get next powerdomain power state - * @pwrdm: struct powerdomain * to get power state - * - * Return the powerdomain @pwrdm's next power state. Returns -EINVAL - * if the powerdomain pointer is null or returns the next power state - * upon success. - */ -int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) -{ - int ret = -EINVAL; - - if (!pwrdm) - return -EINVAL; - - if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst) - ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm); - - return ret; -} - -/** - * pwrdm_read_pwrst - get current powerdomain power state - * @pwrdm: struct powerdomain * to get power state - * - * Return the powerdomain @pwrdm's current power state.Returns -EINVAL - * if the powerdomain pointer is null or returns the current power state - * upon success. Note that if the power domain only supports the ON state - * then just return ON as the current state. - */ -int pwrdm_
[PATCH 04/12] ARM: OMAP2xxx: PM: convert to use the functional power states API
From: Jean Pihet Use the functional power states as the API to control power domains: - use the PWRDM_FUNC_PWRST_* macros for the power states and logic settings, - the function pwrdm_set_next_fpwrst(), which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst() to program the power domains next states, - the function pwrdm_set_fpwrst(), which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state(). Signed-off-by: Jean Pihet [p...@pwsan.com: split the original patch into OMAP2/3/4 variants; fix commit message; update the power state programming to make sense; warn if sets fail] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/pm24xx.c | 24 ++-- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 4c06d8a..29abb63 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -89,8 +89,8 @@ static int omap2_enter_full_retention(void) omap2_prm_write_mod_reg(0x, CORE_MOD, OMAP24XX_PM_WKST2); omap2_prm_write_mod_reg(0x, WKUP_MOD, PM_WKST); - pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); + WARN_ON(pwrdm_set_next_fpwrst(core_pwrdm, PWRDM_FUNC_PWRST_CSWR)); + WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_CSWR)); /* Workaround to kill USB */ l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL; @@ -132,8 +132,8 @@ no_sleep: /* Mask future PRCM-to-MPU interrupts */ omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); - pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON); + WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON)); + WARN_ON(pwrdm_set_next_fpwrst(core_pwrdm, PWRDM_FUNC_PWRST_ON)); return 0; } @@ -184,16 +184,16 @@ static void omap2_enter_mpu_retention(void) omap2_prm_write_mod_reg(0x, WKUP_MOD, PM_WKST); /* Try to enter MPU retention */ - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); - + WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, + PWRDM_FUNC_PWRST_CSWR)); } else { /* Block MPU retention */ - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); + WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON)); } omap2_sram_idle(); - pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); + WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON)); } static int omap2_can_sleep(void) @@ -248,17 +248,13 @@ static void __init prcm_setup_regs(void) for (i = 0; i < num_mem_banks; i++) pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); - pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET); - - pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); - /* Force-power down DSP, GFX powerdomains */ pwrdm = clkdm_get_pwrdm(dsp_clkdm); - pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); + WARN_ON(pwrdm_set_next_fpwrst(pwrdm, PWRDM_FUNC_PWRST_OFF)); pwrdm = clkdm_get_pwrdm(gfx_clkdm); - pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); + WARN_ON(pwrdm_set_next_fpwrst(pwrdm, PWRDM_FUNC_PWRST_OFF)); /* Enable hardware-supervised idle for all clkdms */ clkdm_for_each(omap_pm_clkdms_setup, NULL); -- 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/12] ARM: OMAP2+: PM: use power domain functional state in stats counters
From: Jean Pihet The PM code uses some counters to keep track of the power domains transitions, in order to provide the information to drivers (in pwrdm_get_context_loss_count) and to expose the information to sysfs for debug purpose. This patch provides the information for each functional state. Signed-off-by: Jean Pihet [p...@pwsan.com: use PWRDM_FPWRSTS_COUNT due to functional power state offset; use powerdomain.c fn to convert func pwrsts to names; rename 'state' to 'fpwrst' to indicate use of func pwrsts; convert remaining users of the non-func pwrst API; add some kerneldoc] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/pm-debug.c| 42 - arch/arm/mach-omap2/powerdomain.c | 167 ++--- arch/arm/mach-omap2/powerdomain.h | 17 ++-- 3 files changed, 108 insertions(+), 118 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 806a06b..72cf9e0 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -53,13 +53,6 @@ enum { DEBUG_FILE_TIMERS, }; -static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = { - "OFF", - "RET", - "INA", - "ON" -}; - void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) { s64 t; @@ -70,7 +63,7 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) /* Update timer for previous state */ t = sched_clock(); - pwrdm->state_timer[prev] += t - pwrdm->timer; + pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer; pwrdm->timer = t; } @@ -79,6 +72,7 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) { struct seq_file *s = (struct seq_file *)user; + /* XXX This needs to be implemented in a better way */ if (strcmp(clkdm->name, "emu_clkdm") == 0 || strcmp(clkdm->name, "wkup_clkdm") == 0 || strncmp(clkdm->name, "dpll", 4) == 0) @@ -94,23 +88,26 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) { struct seq_file *s = (struct seq_file *)user; int i; + int curr_fpwrst; if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || strcmp(pwrdm->name, "wkup_pwrdm") == 0 || strncmp(pwrdm->name, "dpll", 4) == 0) return 0; - if (pwrdm->state != pwrdm_read_pwrst(pwrdm)) - printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n", - pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm)); + curr_fpwrst = pwrdm_read_fpwrst(pwrdm); + if (pwrdm->fpwrst != curr_fpwrst) + pr_err("pwrdm state mismatch(%s) %s != %s\n", + pwrdm->name, + pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst), + pwrdm_convert_fpwrst_to_name(curr_fpwrst)); seq_printf(s, "%s (%s)", pwrdm->name, - pwrdm_state_names[pwrdm->state]); - for (i = 0; i < PWRDM_MAX_PWRSTS; i++) - seq_printf(s, ",%s:%d", pwrdm_state_names[i], - pwrdm->state_counter[i]); + pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst)); + for (i = PWRDM_FPWRST_OFFSET; i < PWRDM_MAX_FUNC_PWRSTS; i++) + seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i), + pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]); - seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter); for (i = 0; i < pwrdm->banks; i++) seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, pwrdm->ret_mem_off_counter[i]); @@ -133,11 +130,12 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) pwrdm_state_switch(pwrdm); seq_printf(s, "%s (%s)", pwrdm->name, - pwrdm_state_names[pwrdm->state]); + pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst)); - for (i = 0; i < 4; i++) - seq_printf(s, ",%s:%lld", pwrdm_state_names[i], - pwrdm->state_timer[i]); + for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++) + seq_printf(s, ",%s:%lld", + pwrdm_convert_fpwrst_to_name(i + PWRDM_FPWRST_OFFSET), + pwrdm->fpwrst_timer[i]); seq_printf(s, "\n"); return 0; @@ -209,8 +207,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) t = sched_clock(); - for (i = 0; i < 4; i++) - pwrdm->state_timer[i] = 0; + for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++) + pwrdm->fpwrst_timer[i] = 0; pwrdm->timer = t; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 2c732b6..3e2e263 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -115,97 +115,16 @@ static int _pwrdm_register(struct powerdom
[PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
From: Jean Pihet Introduce the functional states for power domains, which include the power states and the logic states. This patch provides the API functions to set and read the power domains functional state and internal functions to convert between the functional (i.e. logical) and the internal (or registers) values. In the new API only the functions pwrdm_set_next_fpwrst() and pwrdm_set_fpwrst() shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters. Note about the power domains allowed states: Power domains have varied capabilities, as defined by the value of the pwrsts and pwrsts_logic_ret fields of the powerdomain struct. When reading or setting a low power state such as OFF/RET, a specific requested state may not be supported on the given power domain. In the states conversion functions a power or logic state is first looked for in the lower power states in order to maximize the power savings, then if not found in the higher power states. An iteration function is used, as suggested by Rajendra Nayak This function is temporary and will be removed later in the series. This functionality brings consistency in the functional power states core code and acts as a guard against hardware implementations discrepancies, e.g. some power domains only support the RET logic state although reading the logic state registers (previous, current and next) always returns OFF. The DSS power domain on OMAP3 is an example. Signed-off-by: Jean Pihet Cc: Tero Kristo Cc: Rajendra Nayak Cc: Nishanth Menon [p...@pwsan.com: add offset for functional powerstates so it's not possible to confuse them with the old API; use one fn to convert func pwrsts to low-level hardware bits; skip hardware reads when hardware logic retst and logic pwrst bits are missing; fix kerneldoc and commit message; remove unnecessary PWRDM_LOGIC_MEM_PWRST_* macros; combine spinlock patch into this patch; expand the number of operations which take the spinlock] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 525 + arch/arm/mach-omap2/powerdomain.h | 33 ++ 2 files changed, 553 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 94b89a25..18f33de 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -1,7 +1,7 @@ /* * OMAP powerdomain control * - * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc. + * Copyright (C) 2007-2008, 2011-2012 Texas Instruments, Inc. * Copyright (C) 2007-2011 Nokia Corporation * * Written by Paul Walmsley @@ -44,12 +44,19 @@ enum { PWRDM_STATE_PREV, }; - /* pwrdm_list contains all registered struct powerdomains */ static LIST_HEAD(pwrdm_list); static struct pwrdm_ops *arch_pwrdm; +/* + * _fpwrst_names: human-readable functional powerstate names - should match + *the enum pwrdm_func_state order and names + */ +static const char * const _fpwrst_names[] = { + "OFF", "OSWR", "CSWR", "INACTIVE", "ON" +}; + /* Private functions */ static struct powerdomain *_pwrdm_lookup(const char *name) @@ -145,7 +152,6 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm) static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) { - int prev, next, state, trace_state = 0; if (pwrdm == NULL) @@ -259,6 +265,309 @@ static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) return _pwrdm_logic_retst_is_controllable(pwrdm); } +/** + * _match_pwrst: determine the closest supported power state + * @pwrsts: list of allowed states, defined as a bitmask + * @pwrst: initial state to be used as a starting point + * @min: minimum (i.e. lowest consumption) allowed state + * @max: maximum (i.e. highest consumption) allowed state + * + * Search down then up for a valid state from a list of allowed + * states. Used by states conversion functions (_pwrdm_fpwrst_to_*) + * to look for allowed power and logic states for a powerdomain. + * Returns the matching allowed state. XXX Deprecated. The software + * should not try to program unsupported powerstates. + */ +static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max) +{ + int found = 1, new_pwrst = pwrst; + + /* +* If the power domain does not allow any state programmation +* return the max state which is always allowed +*/ + if (!pwrsts) + return max; + + /* +* Search lower: if the requested state is not supported +* try the lower states, stopping at the minimum allowed +* state +*/ + while (!(pwrsts & (1 << new_pwrst))) { + if (new_pwrst <= min) { + found = 0; + break; + } + new_pwrst--; + } + + /* +* Search higher: if no lower state found
[PATCH 00/12] ARM: OMAP2+: powerdomain updates after the functional power state conversion
OMAP powerdomain code updates, implemented on top of the functional power state conversion series. This series fixes the powerdomain handling for OMAP2xxx, adds caching for the powerdomain next-power-state and previous-power-state register bitfields, and some cleanup that's intended to make it easier to move the powerdomain code out to drivers/. - Paul --- vmlinux object size (delta in bytes from TEST_func_powerstates_devel_3.9 (6d8345f4177c976eca1a1368cdd68e95f80c3f27)): text data bsstotal kernel -68 +480 -20 am33xx_only -136 +480 -88 n800_multi_omap2xxx -128 +480 -80 n800_only_a 0000 omap1_defconfig 0000 omap1_defconfig_1510innovator_only 0000 omap1_defconfig_5912osk_only -32 +3680 +336 omap2plus_defconfig +20 +160 +36 omap2plus_defconfig_2430sdp_only -32 +4320 +400 omap2plus_defconfig_cpupm +572 +1920 +764 omap2plus_defconfig_no_pm -20 +2080 +188 omap2plus_defconfig_omap2_4_only -84 +3040 +220 omap2plus_defconfig_omap3_4_only +708 +200 -104 +804 rmk_omap3430_ldp_allnoconfig +352 +1280 +480 rmk_omap3430_ldp_oldconfig +708 +200 -104 +804 rmk_omap4430_sdp_allnoconfig -164 +80 -156 rmk_omap4430_sdp_oldconfig Paul Walmsley (12): ARM: OMAP2+: powerdomain: consolidate arch_pwrdm check code ARM: OMAP2+: PM/powerdomain: move the power state time tracking into the powerdomain code ARM: OMAP2+: powerdomain: split pwrdm_state_switch() ARM: OMAP2+: PM: clean up some debugfs functions ARM: OMAP2+: powerdomain: remove some redundant checks; add some notes ARM: OMAP2+: CM: use the cached copy of the clockdomain's hwsup state ARM: OMAP2+: powerdomain: cache the powerdomain next power state ARM: OMAP2+: powerdomain: cache the powerdomain's previous power state ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on ARM: OMAP2+: powerdomain: skip previous-power-state read if next_pwrst is ON ARM: OMAP2xxx: powerdomain: add previous power state tracking ARM: OMAP2xxx: PM: add pwrdm_(pre|post)_transition() calls to the 2xxx PM code arch/arm/mach-omap2/clockdomain.c | 18 + arch/arm/mach-omap2/clockdomain.h |2 arch/arm/mach-omap2/cm2xxx.c| 19 - arch/arm/mach-omap2/cm3xxx.c| 14 - arch/arm/mach-omap2/pm-debug.c | 101 arch/arm/mach-omap2/pm.h|6 arch/arm/mach-omap2/pm24xx.c|8 + arch/arm/mach-omap2/powerdomain.c | 352 +++ arch/arm/mach-omap2/powerdomain.h | 40 +++ arch/arm/mach-omap2/powerdomains2xxx_data.c |2 arch/arm/mach-omap2/powerdomains33xx_data.c |3 arch/arm/mach-omap2/powerdomains3xxx_data.c |9 - arch/arm/mach-omap2/powerdomains44xx_data.c |5 arch/arm/mach-omap2/prm2xxx.c | 12 + 14 files changed, 347 insertions(+), 244 deletions(-) -- 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 01/12] ARM: OMAP2+: powerdomain: consolidate arch_pwrdm check code
Check for the presence of some of the arch_pwrdm function pointers during powerdomain setup, rather than in the individual functions. The primary motivation is to make the code slightly easier to read, but it also should avoid a few instructions in some hot paths. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 43 +++-- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index f81aee1..b67d721 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -385,9 +385,6 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm, if (!_pwrdm_pwrst_is_controllable(pwrdm)) return 0; - if (!arch_pwrdm || !arch_pwrdm->pwrdm_set_next_pwrst) - return -EINVAL; - if (!(pwrdm->pwrsts & (1 << pwrst))) return -EINVAL; @@ -395,13 +392,11 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm, if (!(pwrdm->pwrsts_logic_ret & (1 << logic))) return -EINVAL; - if (arch_pwrdm->pwrdm_set_logic_retst) { - ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic); - if (ret) { - pr_err("%s: unable to set logic state %0x of powerdomain: %s\n", - __func__, logic, pwrdm->name); - return ret; - } + ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic); + if (ret) { + pr_err("%s: unable to set logic state %0x of powerdomain: %s\n", + __func__, logic, pwrdm->name); + return ret; } } @@ -426,9 +421,6 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm) int next_pwrst, next_logic, ret; u8 fpwrst; - if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst) - return -EINVAL; - next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm); if (next_pwrst < 0) return next_pwrst; @@ -653,9 +645,12 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) * * Register the list of function pointers used to implement the * powerdomain functions on different OMAP SoCs. Should be called - * before any other pwrdm_register*() function. Returns -EINVAL if - * @po is null, -EEXIST if platform functions have already been - * registered, or 0 upon success. + * before any other pwrdm_register*() function. Several function + * pointers in @po are required to be non-null for the powerdomain + * code to function: pwrdm_wait_transition, pwrdm_read_next_pwrst, + * pwrdm_read_pwrst, pwrdm_set_next_pwrst, pwrdm_set_logic_retst, and + * pwrdm_read_prev_pwrst. Returns -EINVAL if @po is null, -EEXIST if + * platform functions have already been registered, or 0 upon success. */ int pwrdm_register_platform_funcs(struct pwrdm_ops *po) { @@ -665,6 +660,11 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *po) if (arch_pwrdm) return -EEXIST; + if (!po->pwrdm_wait_transition || !po->pwrdm_read_next_pwrst || + !po->pwrdm_read_pwrst || !po->pwrdm_set_next_pwrst || + !po->pwrdm_set_logic_retst || !po->pwrdm_read_prev_pwrst) + return -ENOENT; + arch_pwrdm = po; return 0; @@ -1221,7 +1221,7 @@ int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm) int next_pwrst, next_logic, ret; u8 fpwrst; - if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst) + if (!arch_pwrdm) return -EINVAL; pwrdm_lock(pwrdm); @@ -1264,8 +1264,7 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst) int ret = 0; bool hwsup = false; - if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm || - !arch_pwrdm->pwrdm_read_pwrst) + if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm) return -EINVAL; /* @@ -1334,9 +1333,6 @@ int pwrdm_read_fpwrst(struct powerdomain *pwrdm) if (!_pwrdm_pwrst_can_change(pwrdm)) return PWRDM_FUNC_PWRST_ON; - if (!arch_pwrdm->pwrdm_read_pwrst) - return -EINVAL; - pwrdm_lock(pwrdm); ret = _pwrdm_read_fpwrst(pwrdm); pwrdm_unlock(pwrdm); @@ -1362,9 +1358,6 @@ int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) if (!_pwrdm_pwrst_can_change(pwrdm)) return PWRDM_FUNC_PWRST_ON; - if (!arch_pwrdm->pwrdm_read_prev_pwrst) - return -EINVAL; - pwrdm_lock(pwrdm); ret = _pwrdm_read_prev_fpwrst(pwrdm); pwrdm_unlock(pwrdm); -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to maj
[PATCH 02/12] ARM: OMAP2+: PM/powerdomain: move the power state time tracking into the powerdomain code
Move the power state time tracking code into the powerdomain code. This code accesses internal powerdomain state, so this change will allow us to reduce what is exported from the powerdomain code. Signed-off-by: Paul Walmsley Cc: Tero Kristo Cc: Kevin Hilman --- arch/arm/mach-omap2/pm-debug.c| 24 arch/arm/mach-omap2/pm.h |6 -- arch/arm/mach-omap2/powerdomain.c | 22 +- 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 03da2e3..80c001a 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -53,21 +53,6 @@ enum { DEBUG_FILE_TIMERS, }; -void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) -{ - s64 t; - - if (!pm_dbg_init_done) - return ; - - /* Update timer for previous state */ - t = sched_clock(); - - pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer; - - pwrdm->timer = t; -} - static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) { struct seq_file *s = (struct seq_file *)user; @@ -197,17 +182,8 @@ DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) { - int i; - s64 t; struct dentry *d; - t = sched_clock(); - - for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++) - pwrdm->fpwrst_timer[i] = 0; - - pwrdm->timer = t; - if (strncmp(pwrdm->name, "dpll", 4) == 0) return 0; diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 19ef376..c496f27 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -59,12 +59,6 @@ extern u32 enable_off_mode; #define enable_off_mode 0 #endif -#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) -extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); -#else -#define pm_dbg_update_time(pwrdm, prev) do {} while (0); -#endif /* CONFIG_PM_DEBUG */ - /* 24xx */ extern void omap24xx_idle_loop_suspend(void); extern unsigned int omap24xx_idle_loop_suspend_sz; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index b67d721..53bc852 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -20,6 +20,8 @@ #include #include #include +#include + #include #include "cm2xxx_3xxx.h" @@ -126,6 +128,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm) arch_pwrdm->pwrdm_wait_transition(pwrdm); pwrdm->fpwrst = pwrdm_read_fpwrst(pwrdm); pwrdm->fpwrst_counter[pwrdm->fpwrst - PWRDM_FPWRST_OFFSET] = 1; +#ifdef CONFIG_PM_DEBUG + pwrdm->timer = sched_clock(); +#endif return 0; } @@ -579,6 +584,21 @@ static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) return ret; } +/* XXX prev is wrong type */ +/* XXX is sched_clock() correct to use here? */ +/* Update timer for previous state */ +static void _pwrdm_update_pwrst_time(struct powerdomain *pwrdm, int prev) +{ +#ifdef CONFIG_PM_DEBUG + s64 t; + + t = sched_clock(); + + pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer; + + pwrdm->timer = t; +#endif +} /* XXX Caller must hold pwrdm->_lock */ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) @@ -617,7 +637,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) if (fpwrst != prev) pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++; - pm_dbg_update_time(pwrdm, prev); + _pwrdm_update_pwrst_time(pwrdm, prev); pwrdm->fpwrst = fpwrst; -- 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/12] ARM: OMAP2+: powerdomain: remove some redundant checks; add some notes
Remove some redundant tests in static functions, and add some comments to some code that should have future attention. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c | 18 +++--- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 658f4ed..62e2f75 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -95,7 +95,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) int i; struct voltagedomain *voltdm; - if (!pwrdm || !pwrdm->name) + if (!pwrdm->name) return -EINVAL; if (cpu_is_omap44xx() && @@ -528,9 +528,6 @@ static int _pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) { int ret = -EINVAL; - if (!pwrdm) - return -EINVAL; - if (pwrdm->banks < (bank + 1)) return -EEXIST; @@ -566,9 +563,6 @@ static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) { int ret = -EINVAL; - if (!pwrdm) - return -EINVAL; - if (pwrdm->banks < (bank + 1)) return -EEXIST; @@ -635,6 +629,11 @@ static void _pwrdm_state_switch(struct powerdomain *pwrdm) static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused) { + /* +* XXX It should be possible to avoid the clear_all_prev_pwrst +* call for powerdomains if we are programming them to stay on, +* for example. +*/ pwrdm_clear_all_prev_pwrst(pwrdm); _pwrdm_state_switch(pwrdm); return 0; @@ -1000,6 +999,11 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) return ret; /* +* XXX Is there some way for us to skip powerdomains that +* don't have a prev pwrst register? +*/ + + /* * XXX should get the powerdomain's current state here; * warn & fail if it is not ON. */ -- 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/12] ARM: OMAP2+: powerdomain: split pwrdm_state_switch()
Move the pwrdm_state_switch() code that deals with previous power states into the post-transition callback. This improves the clarity of pwrdm_state_switch() considerably. Add some sorely-needed kerneldoc for these functions. It should be possible to drop pwrdm_state_switch() completely during 3.9. Signed-off-by: Paul Walmsley Cc: Tero Kristo --- arch/arm/mach-omap2/powerdomain.c | 118 - arch/arm/mach-omap2/powerdomain.h |1 2 files changed, 76 insertions(+), 43 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 53bc852..d38f493 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -40,11 +40,6 @@ #define PWRDM_TRACE_STATES_FLAG(1<<31) -enum { - PWRDM_STATE_NOW = 0, - PWRDM_STATE_PREV, -}; - /* Types of sleep_switch used in pwrdm_set_fpwrst() */ #define ALREADYACTIVE_SWITCH 0 #define FORCEWAKEUP_SWITCH 1 @@ -600,60 +595,97 @@ static void _pwrdm_update_pwrst_time(struct powerdomain *pwrdm, int prev) #endif } -/* XXX Caller must hold pwrdm->_lock */ -static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) +/** + * _pwrdm_state_switch - record powerdomain usage data; track power state + * (before powerdomain state transition) + * @pwrdm: struct powerdomain * to observe + * + * If the powerdomain @pwrdm's current power state is not what we last + * observed it to be, then increment the counter for that power state. + * This is used to track context loss events, and for debugging. Also + * if CONFIG_PM_DEBUG=y, track the amount of time the powerdomain has + * spent in the current power state. Caller must hold pwrdm->_lock. + * Intended to be called immediately before the powerdomain's power + * state is likely to change. XXX Note that the counts and durations + * observed by this function may be inaccurate. Powerdomains can + * transition power states automatically, without the kernel being + * involved -- for example, a device can DMA data from memory while + * the MPU is asleep. This function does not attempt to account for + * that. XXX It may be possible to skip this function completely if + * PM debugging is not needed and off-mode and OSWR is disabled (e.g., + * no context loss events). No return value. + */ +static void _pwrdm_state_switch(struct powerdomain *pwrdm) { - int prev, next, fpwrst, trace_state = 0; - - if (pwrdm == NULL) - return -EINVAL; + int fpwrst; fpwrst = _pwrdm_read_fpwrst(pwrdm); - - switch (flag) { - case PWRDM_STATE_NOW: - prev = pwrdm->fpwrst; - break; - case PWRDM_STATE_PREV: - prev = _pwrdm_read_prev_fpwrst(pwrdm); - if (pwrdm->fpwrst != prev) - pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++; - /* -* If the power domain did not hit the desired state, -* generate a trace event with both the desired and hit states -*/ - next = _pwrdm_read_next_fpwrst(pwrdm); - if (next != prev) { - trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 | - prev); - trace_power_domain_target(pwrdm->name, trace_state, - smp_processor_id()); - } - break; - default: - return -EINVAL; - } - - if (fpwrst != prev) + if (fpwrst != pwrdm->fpwrst) pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++; - _pwrdm_update_pwrst_time(pwrdm, prev); + _pwrdm_update_pwrst_time(pwrdm, pwrdm->fpwrst); pwrdm->fpwrst = fpwrst; - - return 0; } static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused) { pwrdm_clear_all_prev_pwrst(pwrdm); - _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); + _pwrdm_state_switch(pwrdm); return 0; } +/** + * _pwrdm_post_transition_cb - record powerdomain usage data; track power state + * (after powerdomain power state transition) + * @pwrdm: struct powerdomain * to observe + * + * If the powerdomain @pwrdm's previous power state doesn't match our + * recollection of the powerdomain's current power state, then + * increment the counter for the previous power state. And if the + * powerdomain's previous power state doesn't match the current power + * state, increment the counter for the current power state. This + * function is used to track context loss events, and for debugging. + * Also if CONFIG_PM_DEBUG=y, track the approximate amount of time the + * powerdomain has spent in the previous power state. Caller must + * hold pwrdm->_lock. XXX Note that the counts and durations observed + * by this function may be inaccurate. Powerdomains can transition + * power states
[PATCH 04/12] ARM: OMAP2+: PM: clean up some debugfs functions
Move some debugfs functions into the powerdomain and clockdomain code; the ultimate goal is to stop exporting some of the powerdomain/clockdomain functions. Get rid of the nasty hacks that avoid executing some of the debug functions based on string comparisons on powerdomain and clockdomain names. Lock the powerdomain for the duration of these functions so that the debug information doesn't change during execution. Also, while here, fix a whitespace issue in mach-omap2/pm-debug.c. Signed-off-by: Paul Walmsley Cc: Tero Kristo Cc: Kevin Hilman --- arch/arm/mach-omap2/clockdomain.c | 18 +++- arch/arm/mach-omap2/clockdomain.h |2 + arch/arm/mach-omap2/pm-debug.c| 77 ++ arch/arm/mach-omap2/powerdomain.c | 85 + arch/arm/mach-omap2/powerdomain.h |4 ++ 5 files changed, 111 insertions(+), 75 deletions(-) diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index a90c0c8..bc9b79e 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -22,9 +22,8 @@ #include #include #include - +#include #include - #include #include "soc.h" @@ -1281,3 +1280,18 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) return _clkdm_clk_hwmod_disable(clkdm); } +/* Clockdomain debugfs functions */ + +int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *seq_file) +{ + struct seq_file *s = (struct seq_file *)seq_file; + + if (!clkdm->flags) + return 0; + + seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name, + clkdm->usecount); + + return 0; +} + diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index 2da3765..95e473b 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -229,4 +229,6 @@ extern struct clkdm_dep gfx_24xx_wkdeps[]; extern struct clkdm_dep dsp_24xx_wkdeps[]; extern struct clockdomain wkup_common_clkdm; +extern int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *seq_file); + #endif diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 80c001a..9861069 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -53,75 +53,6 @@ enum { DEBUG_FILE_TIMERS, }; -static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) -{ - struct seq_file *s = (struct seq_file *)user; - - /* XXX This needs to be implemented in a better way */ - if (strcmp(clkdm->name, "emu_clkdm") == 0 || - strcmp(clkdm->name, "wkup_clkdm") == 0 || - strncmp(clkdm->name, "dpll", 4) == 0) - return 0; - - seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name, - clkdm->usecount); - - return 0; -} - -static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) -{ - struct seq_file *s = (struct seq_file *)user; - int i; - int curr_fpwrst; - - if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || - strcmp(pwrdm->name, "wkup_pwrdm") == 0 || - strncmp(pwrdm->name, "dpll", 4) == 0) - return 0; - - curr_fpwrst = pwrdm_read_fpwrst(pwrdm); - if (pwrdm->fpwrst != curr_fpwrst) - pr_err("pwrdm state mismatch(%s) %s != %s\n", - pwrdm->name, - pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst), - pwrdm_convert_fpwrst_to_name(curr_fpwrst)); - - seq_printf(s, "%s (%s)", pwrdm->name, - pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst)); - for (i = PWRDM_FPWRST_OFFSET; i < PWRDM_MAX_FUNC_PWRSTS; i++) - seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i), - pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]); - - seq_printf(s, "\n"); - - return 0; -} - -static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) -{ - struct seq_file *s = (struct seq_file *)user; - int i; - - if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || - strcmp(pwrdm->name, "wkup_pwrdm") == 0 || - strncmp(pwrdm->name, "dpll", 4) == 0) - return 0; - - pwrdm_state_switch(pwrdm); - - seq_printf(s, "%s (%s)", pwrdm->name, - pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst)); - - for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++) - seq_printf(s, ",%s:%lld", - pwrdm_convert_fpwrst_to_name(i + PWRDM_FPWRST_OFFSET), - pwrdm->fpwrst_timer[i]); - - seq_printf(s, "\n"); - return 0; -} - static int pm_dbg_show_counters(struct seq_file *s, void *unused) { pwrdm_for_each(pwrdm_dbg_show_counter, s); @@ -150,10 +81,10 @@ static int pm_dbg_open(struct inode *inode, struct file *file) } static
[PATCH 06/12] ARM: OMAP2+: CM: use the cached copy of the clockdomain's hwsup state
Avoid some unnecessary CM IP block reads by using the cached copy of the clockdomain's hardware-supervised idle state. This should simplify the code slightly and save a few hundred nanoseconds in these paths. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cm2xxx.c | 19 ++- arch/arm/mach-omap2/cm3xxx.c | 14 ++ 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index 6774a53..8ca13cd 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -285,14 +285,7 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm) static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) { - bool hwsup = false; - - if (!clkdm->clktrctrl_mask) - return 0; - - hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) + if (!clkdm_in_hwsup(clkdm) && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) omap2xxx_clkdm_wakeup(clkdm); return 0; @@ -300,15 +293,7 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm) { - bool hwsup = false; - - if (!clkdm->clktrctrl_mask) - return 0; - - hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - - if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP) + if (!clkdm_in_hwsup(clkdm) && clkdm->flags & CLKDM_CAN_FORCE_SLEEP) omap2xxx_clkdm_sleep(clkdm); return 0; diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 9061c30..75872134 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -227,8 +227,6 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm) static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) { - bool hwsup = false; - if (!clkdm->clktrctrl_mask) return 0; @@ -243,10 +241,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) return 0; } - hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - - if (hwsup) { + if (clkdm_in_hwsup(clkdm)) { /* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -263,8 +258,6 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) { - bool hwsup = false; - if (!clkdm->clktrctrl_mask) return 0; @@ -280,10 +273,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) return 0; } - hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - - if (hwsup) { + if (clkdm_in_hwsup(clkdm)) { /* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); -- 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 12/12] ARM: OMAP2xxx: PM: add pwrdm_(pre|post)_transition() calls to the 2xxx PM code
The OMAP2xxx PM code was missing calls to pwrdm_pre_transition() and pwrdm_post_transition(). This prevented the power state debugging from working correctly, and also violated some assumptions that are used in future power state caching patches. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/pm24xx.c |8 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 99c16c2..896727c 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -98,6 +98,8 @@ static int omap2_enter_full_retention(void) omap2_gpio_prepare_for_idle(0); + pwrdm_pre_transition(NULL); + /* One last check for pending IRQs to avoid extra latency due * to sleeping unnecessarily. */ if (omap_irq_pending()) @@ -109,6 +111,8 @@ static int omap2_enter_full_retention(void) OMAP_SDRC_REGADDR(SDRC_POWER)); no_sleep: + pwrdm_post_transition(NULL); + omap2_gpio_resume_after_idle(); clk_enable(osc_ck); @@ -191,8 +195,12 @@ static void omap2_enter_mpu_retention(void) WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON)); } + pwrdm_pre_transition(mpu_pwrdm); + omap2_sram_idle(); + pwrdm_post_transition(mpu_pwrdm); + WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON)); } -- 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/12] ARM: OMAP2+: powerdomain: skip previous-power-state read if next_pwrst is ON
If the powerdomain's next-power-state is set to ON, then we can skip the powerdomain previous-power-state read during pwrdm_post_transition(). This is both an optimization (for all OMAPs) and a fix (for OMAP2xxx). It turns out the OMAP2xxx previous power state mechanism is slightly different than the OMAP3+ mechanism. The bitfield can't be cleared, and it's only updated after a powerdomain power state transition. So reading this value before any powerdomain power state transition occurred will always return OFF (the reset value). After this patch, if the power domain was programmed to stay ON before pwrdm_pre_transition() is called, the previous power state code will return ON during pwrdm_post_transition(). Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/powerdomain.c |4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index a4bb0bb..72d6ce0 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -681,7 +681,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) int prev, fpwrst; int trace_state = 0; - prev = _pwrdm_read_prev_fpwrst(pwrdm); + prev = (pwrdm->next_fpwrst == PWRDM_FUNC_PWRST_ON) ? + PWRDM_FUNC_PWRST_ON : _pwrdm_read_prev_fpwrst(pwrdm); + if (pwrdm->fpwrst != prev) pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++; -- 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/12] ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/powerdomain.c |9 ++--- arch/arm/mach-omap2/powerdomain.h |4 arch/arm/mach-omap2/powerdomains2xxx_data.c |2 ++ arch/arm/mach-omap2/powerdomains33xx_data.c |3 ++- arch/arm/mach-omap2/powerdomains3xxx_data.c |9 ++--- arch/arm/mach-omap2/powerdomains44xx_data.c |5 - 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index f5e2727..a4bb0bb 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -462,7 +462,8 @@ static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm) int pwrst, logic_pwrst, ret; u8 fpwrst; - if (!_pwrdm_pwrst_can_change(pwrdm)) + if (!_pwrdm_pwrst_can_change(pwrdm) || + pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL) return PWRDM_FUNC_PWRST_ON; pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm); @@ -1104,12 +1105,14 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) int pwrdm_state_switch_nolock(struct powerdomain *pwrdm) { - int ret; + int ret = 0; if (!pwrdm || !arch_pwrdm) return -EINVAL; - ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); + if (!(pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL)) + ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); + if (!ret) _pwrdm_state_switch(pwrdm); diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index f4a189a..10941fd 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -78,10 +78,14 @@ enum pwrdm_func_state { * * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state * to a lower sleep state without waking up the powerdomain + * + * PWRDM_ACTIVE_WITH_KERNEL - this powerdomain's current power state is + * guaranteed to be ON whenever the kernel is running */ #define PWRDM_HAS_HDWR_SAR BIT(0) #define PWRDM_HAS_MPU_QUIRKBIT(1) #define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2) +#define PWRDM_ACTIVE_WITH_KERNEL BIT(3) /* * Powerdomain internal flags (struct powerdomain._flags) diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c index 578eef8..112927f 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c @@ -54,6 +54,7 @@ static struct powerdomain mpu_24xx_pwrdm = { [0] = PWRSTS_ON, }, .voltdm = { .name = "core" }, + .flags= PWRDM_ACTIVE_WITH_KERNEL, }; static struct powerdomain core_24xx_pwrdm = { @@ -73,6 +74,7 @@ static struct powerdomain core_24xx_pwrdm = { [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ }, .voltdm = { .name = "core" }, + .flags= PWRDM_ACTIVE_WITH_KERNEL, }; diff --git a/arch/arm/mach-omap2/powerdomains33xx_data.c b/arch/arm/mach-omap2/powerdomains33xx_data.c index 869adb8..acb148a 100644 --- a/arch/arm/mach-omap2/powerdomains33xx_data.c +++ b/arch/arm/mach-omap2/powerdomains33xx_data.c @@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = { .pwrstst_offs = AM33XX_PM_MPU_PWRSTST_OFFSET, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL), .banks = 3, .logicretstate_mask = AM33XX_LOGICRETSTATE_MASK, .mem_on_mask= { diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c index f0e14e9ef..ade93d3 100644 --- a/arch/arm/mach-omap2/powerdomains3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c @@ -58,7 +58,7 @@ static struct powerdomain mpu_3xxx_pwrdm = { .prcm_offs= MPU_MOD, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags= PWRDM_HAS_MPU_QUIRK, + .flags= (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL), .banks= 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, @@ -74,7 +74,7 @@ static struct powerdomain mpu_am35x_pwrdm = { .prcm_offs= MPU_MOD, .pwrsts = PWRSTS_ON, .pwrsts_logic_ret = PWRSTS_ON, - .flags= PWRDM_HAS_MPU_QUIRK, +
[PATCH 11/12] ARM: OMAP2xxx: powerdomain: add previous power state tracking
The OMAP2xxx PRM does support a form of powerdomain previous-power-state tracking; so add it. This allows the power state tracking and debugging code to do something useful on this platform. Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/prm2xxx.c | 12 1 file changed, 12 insertions(+) diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index e4cdb69..2d3c905 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -180,10 +180,22 @@ static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm) return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); } +static int omap2xxx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) +{ + u8 omap2xxx_pwrst; + + omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, + OMAP2_PM_PWSTST, + OMAP24XX_LASTSTATEENTERED_MASK); + + return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); +} + struct pwrdm_ops omap2_pwrdm_operations = { .pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst, .pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst, + .pwrdm_read_prev_pwrst = omap2xxx_pwrdm_read_prev_pwrst, .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, .pwrdm_set_mem_retst= omap2_pwrdm_set_mem_retst, -- 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/12] ARM: OMAP2+: powerdomain: cache the powerdomain's previous power state
Cache the powerdomain previous power state registers. The objective here is to avoid unneeded reads from the previous power state registers. Reads from these registers can be extremely slow, even by I/O device standards. I no longer recall the exact measurements, but my recollection was that they cost several microseconds. The cache is invalidated as part of the powerdomain pre-transition code, which runs shortly before WFI/WFE. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/powerdomain.c |9 + arch/arm/mach-omap2/powerdomain.h | 14 ++ 2 files changed, 23 insertions(+) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 425c868..f5e2727 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -499,6 +499,9 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) if (!_pwrdm_pwrst_can_change(pwrdm)) return PWRDM_FUNC_PWRST_ON; + if (pwrdm->_flags & _PWRDM_PREV_FPWRST_IS_VALID) + return pwrdm->prev_fpwrst; + pwrst = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm); if (pwrst < 0) return pwrst; @@ -512,6 +515,10 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) } ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst); + if (!ret) { + pwrdm->prev_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_PREV_FPWRST_IS_VALID; + } return (ret) ? ret : fpwrst; } @@ -1017,6 +1024,8 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) pr_debug("powerdomain: %s: clearing previous power state reg\n", pwrdm->name); + pwrdm->_flags &= ~_PWRDM_PREV_FPWRST_IS_VALID; + if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst) ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm); diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 1fb21f5..f4a189a 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -90,8 +90,17 @@ enum pwrdm_func_state { *powerdomain's next-functional-power-state -- struct *powerdomain.next_fpwrst -- is valid. If this bit is not set, *the code needs to load the current value from the hardware. + * + * _PWRDM_PREV_FPWRST_IS_VALID: the locally-cached copy of the + *powerdomain's previous-functional-power-state -- struct + *powerdomain.prev_fpwrst -- is valid. If this bit is not set, + *the code needs to load the current value from the hardware. The + *previous-functional-power-state cache for the CORE and MPU needs + *to be invalidated right before WFI, unless they were not programmed + *to change power states. */ #define _PWRDM_NEXT_FPWRST_IS_VALIDBIT(0) +#define _PWRDM_PREV_FPWRST_IS_VALIDBIT(1) /* * Number of memory banks that are power-controllable. On OMAP4430, the @@ -138,6 +147,7 @@ struct powerdomain; * @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans) * @fpwrst_counter: estimated number of times the pwrdm entered the power states * @next_fpwrst: cache of the powerdomain's next-power-state + * @prev_fpwrst: cache of the powerdomain's previous-power-state bitfield * @timer: sched_clock() timestamp of last pwrdm_state_switch() * @fpwrst_timer: estimated nanoseconds of residency in the various power states * @_lock: spinlock used to serialize powerdomain and some clockdomain ops @@ -146,6 +156,9 @@ struct powerdomain; * * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. * + * @prev_fpwrst is updated during pwrdm_pre_transition(), but presumably + * should also be updated upon clock/IP block idle transitions. + * * Possible values for @_flags are documented above in the * "Powerdomain internal flags (struct powerdomain._flags)" comments. */ @@ -165,6 +178,7 @@ struct powerdomain { const u8 prcm_partition; u8 fpwrst; u8 next_fpwrst; + u8 prev_fpwrst; u8 _flags; struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS]; struct list_head node; -- 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/12] ARM: OMAP2+: powerdomain: cache the powerdomain next power state
Cache the powerdomain next power state registers. The objective here is to avoid unneeded reads and writes to the next power state registers, which are slow compared to RAM & CPU cache. Signed-off-by: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/powerdomain.c | 64 + arch/arm/mach-omap2/powerdomain.h | 17 ++ 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 62e2f75..425c868 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -376,7 +376,7 @@ static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic, * software-controllable, returns 0; otherwise, passes along the * return value from pwrdm_set_logic_retst() if there is an error * returned by that function, otherwise, passes along the return value - * from pwrdm_set_next_pwrst() + * from pwrdm_set_next_fpwrst() */ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm, u8 logic, u8 pwrst) @@ -426,6 +426,9 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm) int next_pwrst, next_logic, ret; u8 fpwrst; + if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID) + return pwrdm->next_fpwrst; + next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm); if (next_pwrst < 0) return next_pwrst; @@ -438,6 +441,10 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm) return next_logic; } ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst); + if (!ret) { + pwrdm->next_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID; + } return (ret) ? ret : fpwrst; } @@ -663,7 +670,7 @@ static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused) */ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) { - int prev, next, fpwrst; + int prev, fpwrst; int trace_state = 0; prev = _pwrdm_read_prev_fpwrst(pwrdm); @@ -676,10 +683,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) * If the power domain did not hit the desired state, * generate a trace event with both the desired and hit states */ - next = _pwrdm_read_next_fpwrst(pwrdm); - if (next != prev) { - trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 | - prev); + if (pwrdm->next_fpwrst != prev) { + trace_state = (PWRDM_TRACE_STATES_FLAG | + pwrdm->next_fpwrst << 8 | prev); trace_power_domain_target(pwrdm->name, trace_state, smp_processor_id()); } @@ -1256,6 +1262,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst) if (ret) return ret; + if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID && + pwrdm->next_fpwrst == fpwrst) + return 0; + pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst, pwrdm->name); @@ -1264,6 +1274,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst) pwrdm_lock(pwrdm); ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst); + if (!ret) { + pwrdm->next_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID; + } pwrdm_unlock(pwrdm); return ret; @@ -1279,36 +1293,16 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst) */ int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm) { - int next_pwrst, next_logic, ret; - u8 fpwrst; + int ret; - if (!arch_pwrdm) + if (!pwrdm) return -EINVAL; pwrdm_lock(pwrdm); - - next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm); - if (next_pwrst < 0) { - ret = next_pwrst; - goto prnf_out; - } - - next_logic = next_pwrst; - if (_pwrdm_logic_retst_can_change(pwrdm) && - arch_pwrdm->pwrdm_read_logic_pwrst) { - next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm); - if (next_logic < 0) { - ret = next_logic; - goto prnf_out; - } - } - - ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst); - -prnf_out: + ret = _pwrdm_read_next_fpwrst(pwrdm); pwrdm_unlock(pwrdm); - return (ret) ? ret : fpwrst; + return ret; } /** @@ -1344,10 +1338,6 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst) pwrdm_lock(pwrdm); - /* -* XXX quite heavyweight for what this is intended to
Re: [PATCH] ARM: OMAP4: Fix EMU clock domain always on
Hi Jon, On Fri, 7 Dec 2012, Jon Hunter wrote: > Commit d043d87 (ARM: OMAP2+: clockdomain: bypass clockdomain handling > when disabling unused clks) skips the decrementing of a clock-domains > use count if the clocks use count is zero. However, for OMAP4 devices > this is causing the EMU clock-domain to be stuck ON as the use count is > not getting decremented correctly. Thanks for the fix and the great patch description; queued for v3.8-rc. - Paul -- 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
Re: [PATCH V2 0/4] ARM: OMAP4: Clock fixes
On Mon, 3 Dec 2012, Jon Hunter wrote: > Fixes included, fixing up timer clock aliases for v3.8 and working > around ABE DPLL issue seen with latest u-boot bootloader (v2012.10). > > Testing includes: > - Boot testing on OMAP4460 Panda and verifying that all dmtimers are > working. > > V2 changes: > - Updated series to latest ARM-SoC for-next branch that includes common > clock updates for OMAP4. > - Added new function table for non-M4X DPLLs which is now required after > enhancing support for OMAP4 DPLLs for 4X multiplier. Thanks, queued for 3.8-rc. - Paul -- 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
Testing the powerdomain changes
Hi, in case anyone is interested in trying out the recent powerdomain & PM changes, posted for 3.9, there's a temporary branch "TEST_pwrdm_post_fpwrst_devel_a_3.9" in the git tree git://git.pwsan.com/linux-2.6. It's based on the PRCM cleanup branches for v3.7, plus some old regression workarounds needed since the base is v3.7-rc2. Once 3.8 comes out, this branch will be rebased there ASAP, assuming we don't have another huge set of regressions... - Paul -- 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
About 1-Wire driver of OMAP4
Hi, I implemented gas gauge driver by 1-Wire interface in OMAP4 CPU, the driver we used is a GPIO pin to simulate 1-Wire bus but it sometimes can't work well of timing issue. So we want to use HDQ/1Wire controller in OMAP4, does anyone have experience of OMAP4 1-Wire driver of using its controller? Our gas gauge is DS2780 and we use "android-omap-3.0" kernel branch. I tried to do below steps but it still can't work. Or do you have any suggestion? Thanks. 1. Add hwmod of hdq1w in omap_hwmod_44xx_data.c file 2. Use omap_hdq.c file 3. Select "CONFIG_HDQ_MASTER_OMAP", "CONFIG_W1", "CONFIG_HDQ_MASTER_OMAP" and "CONFIG_BATTERY_DS2780" in menuconfig. Regards, Herman -- 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
RE: [PATCH v3 2/3] mtd: devices: elm: Add support for ELM error correction
On Fri, Dec 07, 2012 at 16:07:23, Nori, Sekhar wrote: > On 11/29/2012 5:16 PM, Philip, Avinash wrote: > > The ELM hardware module can be used to speedup BCH 4/8/16 ECC scheme > > error correction. > > For now only 4 & 8 bit support is added > > > > Signed-off-by: Philip, Avinash > > Cc: Grant Likely > > Cc: Rob Herring > > Cc: Rob Landley [...] /** > > + * elm_config - Configure ELM module > > + * @info: elm info > > + */ > > +static void elm_config(struct elm_info *info) > > This is called "config", but there is no configuration information > passed which looks odd.. The config information is bch_type, encapsulated in struct elm_info. > > > +{ > > + u32 reg_val; > > + > > + reg_val = (info->bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16); > > + elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val); > > +} > > Is there a use case where BCH type needs to be changed after NAND has > been probed? No, I think kernel handles the entire NAND part with a single ecc layout. Hence there is no run time BCH switching. But ELM driver should support BCH 4 & 8. Selection of BCH information comes from DT of NAND driver. As NAND driver supporting BCH4 & 8 ecc scheme ELM module support configuration of both. Configuration of ELM module should done as part of NAND driver probing. > You will have to erase any existing data written to NAND if > you change the ECC type. That sounds destructive enough to avoid such a > thing. There is no support for BCH switching after NAND driver probing. [...] > > +struct device *elm_request(enum bch_ecc bch_type) > > +{ > > + struct elm_info *info; > > + > > + list_for_each_entry(info, &elm_devices, list) { > > + if (info && info->dev) { > > + info->bch_type = bch_type; > > + elm_config(info); > > + return info->dev; > > + } > > + } > > This will always return the first ELM device probed since you never > remove the allocated device from the list. But now I realized that, there is no mechanism of freeing the requested resource. So I will add mechanism to request ELM module successfully only if ELM module is not requested already and add mechanism to free it, on NAND driver module unload (loadable module support). This way ELM driver can achieve multi instance support. > I wonder why you really need a list? The prime motivation for the list is the driver should support multi instances of ELM by removing global symbols. Thanks Avinash > > Thanks, > Sekhar > N�r��yb�X��ǧv�^�){.n�+{��f��{ay�ʇڙ�,j��f���h���z��w��� ���j:+v���w�j�mzZ+�ݢj"��!�i
RE: [PATCH v3 1/3] mtd: nand: omap2: Update nerrors using ecc.strength
On Fri, Dec 07, 2012 at 16:10:04, Nori, Sekhar wrote: > On 12/5/2012 6:13 PM, Philip, Avinash wrote: > > On Wed, Dec 05, 2012 at 17:33:37, Nori, Sekhar wrote: > >> Hi Avinash, > >> > >> On 11/29/2012 5:16 PM, Philip, Avinash wrote: > >>> Update number of errors using nand ecc strength. > >>> Also add macro definitions BCH8_ERROR_MAX & BCH4_ERROR_MAX > >> > >> Can you please describe why the original method of setting nerrors was > >> incorrect? Was it causing any issues in any particular configuration? > > > > It affects the reusability of the code. For example BCH8 with AM335x RBL > > compatibility requires 14 bytes instead of 13 byte. So setting nerrors > > with > > nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4; > > will break am335x RBL compatibility. > > This should be summarized in the patch description so the motivation is > clear to those who read the history later. Ok I will add the details in patch description in next version. Thanks Avinash > > Thanks, > Sekhar >
RE: [rtc-linux] [PATCH v3 1/5] rtc: OMAP: Add system pm_power_off to rtc driver
On Wed, Nov 28, 2012 at 16:42:26, Russell King - ARM Linux wrote: > On Tue, Nov 27, 2012 at 03:42:39PM -0800, Andrew Morton wrote: > > > + /* Do not allow to execute any other task */ > > > + spin_lock_irqsave(&lock, flags); > > > + while (1); > > > > I suspect this doesn't do what you want it to do. > > > > Firstly, please provide adequate code comments here so that code > > readers do not also need to be mind readers. > > > > If you want to stop this CPU dead in its tracks (why?) then > > > > local_irq_disable(); > > while (1) > > ; /* Note correct code layout */ > > > > will do it. But it means that the NMI watchdog (if present) will come > > along and whack the machine in the head a few seconds later. And this > > does nothing to stop other CPUs. > > > > But not being a mind reader, I'm really at a loss to suggest what > > should be done here. Here intention is to disable all interrupts between rtc power_off request till system actually went to power off mode, max 2 seconds based on when the AM335x RTC alarm2 expires. The idea was that since the system is going to shutdown, it is better to not process any more interrupts. > It's hooking into the pm_power_off hook, which is called from kernel/sys.c > via arch code. We will have already stopped all other CPUs at this point. > > Why there's that while (1) there I don't know; when pm_power_off is not > hooked, we don't do anything like that - and what will happen in that > case is we'll return all the way back to sys_reboot(), which will call > do_exit(0) on us. When testing with v3.7-rc7, I saw the following BUG() triggered when I did not use a while(1). Logs below. Before calling do_exit(0), there is a reboot_mutex lock that is taken in reboot syscall. do_exit() function is , checking for any locks held by the processor and if yes then it is printing a BUG_ON from print_held_locks_bug() function along with the locks held information. Even though the BUG triggers, the system is going to power off because The hardware has been triggered. (log) [root@arago /]# poweroff The system is going down NOW! Sent SIGTERM to all processes Sent SIGKILL to all processes Requesting system poweroff [ 32.125900] Disabling non-boot CPUs ... [ 32.130155] Power down. [ 32.132741] System will go to power_off state in approx. 2 secs [ 32.139994] [ 32.141575] = [ 32.146564] [ BUG: lock held at task exit time! ] [ 32.151522] 3.7.0-rc7-00015-g3f8bbe0 #32 Not tainted [ 32.156721] - [ 32.161676] init/622 is exiting with locks still held! [ 32.167085] 1 lock held by init/622: [ 32.170831] #0: (reboot_mutex){+.+...}, at: [] sys_reboot+0xf4/0x1e8 [ 32.178679] [ 32.178679] stack backtrace: [ 32.183305] [] (unwind_backtrace+0x0/0xf0) from [] (do_exit+0x488/0x7e8) [ 32.192183] [] (do_exit+0x488/0x7e8) from [] (sys_reboot+0x100/0x1e8) [ 32.200797] [] (sys_reboot+0x100/0x1e8) from [] (ret_fast_syscall+0x0/0x3c) = It is not clear to me where reboot_mutex should have been unlocked before debug_check_no_locks_held() is called in do_exit()? Note: In latest linux-next tip I am *not* seeing this error. I have not bisected yet to see what fixed this. Since with latest linux-next I am not seeing an issue, I will remove spinlock and the while(1). Hope that will make the patch more acceptable. > I don't see a problem with that, and I don't see why we need to spin > (without any power saving too) waiting for some event. If we've called > sys_reboot with LINUX_REBOOT_CMD_POWER_OFF, we'd better have already > killed most of userspace off by that time anyway. > I did a search of various power-off implementations in *arch/arm*. Those that use a while(1): = arch/arm/mach-at91/board-gsia18s.c arch/arm/mach-at91/setup.c doesn't arch/arm/mach-cns3xxx/cns3420vb.c arch/arm/mach-iop32x/glantank.c arch/arm/mach-iop32x/iq31244.c arch/arm/mach-iop32x/n2100.c local_irq_disable() and then a while(1) arch/arm/mach-kirkwood/board-lsxl.c arch/arm/mach-highbank/highbank.c does while(1) cpu_do_idle() Those that don't have a while(1): arch/arm/mach-imx/mach-mx31moboard.c arch/arm/mach-iop32x/em7210.c Doesn't have a while(1) but setting a gpio so presumably kills the system immediately: === arch/arm/mach-ixp4xx/dsmg600-setup.c arch/arm/mach-ixp4xx/nas100d-setup.c arch/arm/mach-ixp4xx/nslu2-setup.c arch/arm/mach-kirkwood/board-dnskw.c arch/arm/mach-kirkwood/board-ib62x0.c arch/arm/mach-kirkwood/board-dnskw.c arch/arm/mach-kirkwood/board-ib62x0.c arch/arm/mach-kirkwood/d2net_v2-setup.c arch/arm/mach-kirkwood/netspace_v2-setup.c arch/arm/mach-kirkwood/netxbig_v2-setup.c arch/arm/mach-kirkwood/t5325-setup.c arch/arm/mach-orion5x/dns323-setup.c arch/arm/mach-vexpress/v2m.c take a spinlock, not sure when it will shut down arch/arm/mach-kirkwood/board-ts219.c sends a character to PIC
[PATCH 0/9] memory: emif: miscellaneous bug fixes for EMIF driver
This series resolves a few minor issues for EMIF driver. Tested all the patches on OMAP4-sdp, OMAP5-sevm. Patch : "memory: emif: setup LP settings on freq update" is tested on a local tree, since freq update cannot be tested on mainline. Ambresh K (1): memory: emif: use default custom config parameter. Lokesh Vutla (1): memory: emif: Correct the lpmode timeout calculation Nishanth Menon (5): memory: emif: setup LP settings on freq update memory: emif: handle overflow for timing for LP mode memory: emif: Handle devices which are not rated for >85C memory: emif: use restart if power_off not present when out of spec memory: emif: disable phy_fast_dll_lock Oleksandr Dmytryshyn (1): memory: emif: fix timings initialization issue Severine Glock (1): memory: emif: debugfs: Remove MR4= string print drivers/memory/emif.c | 92 +-- drivers/memory/emif.h |2 +- include/linux/platform_data/emif_plat.h |1 + 3 files changed, 78 insertions(+), 17 deletions(-) -- 1.7.9.5 -- 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/9] memory: emif: setup LP settings on freq update
From: Nishanth Menon Program the power management shadow register on freq update else the concept of threshold frequencies dont really matter as the system always uses the performance mode timing for LP which is programmed in at init time. Signed-off-by: Nishanth Menon --- drivers/memory/emif.c |5 + 1 file changed, 5 insertions(+) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 8589aba..69a480d 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -815,6 +815,11 @@ static void setup_registers(struct emif_data *emif, struct emif_regs *regs) writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW); writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW); + if (emif->lpmode != EMIF_LP_MODE_DISABLE) { + writel(regs->pwr_mgmt_ctrl_shdw, + base + EMIF_POWER_MANAGEMENT_CTRL_SHDW); + } + /* Settings specific for EMIF4D5 */ if (emif->plat_data->ip_rev != EMIF_4D5) return; -- 1.7.9.5 -- 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/9] memory: emif: debugfs: Remove MR4= string print
From: Severine Glock MR4 is reported under debugfs with following format MR4=%d. Remove MR4= string for better convenience. Signed-off-by: Severine Glock --- drivers/memory/emif.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 625732d..32ce601 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -147,7 +147,7 @@ static int emif_mr4_show(struct seq_file *s, void *unused) { struct emif_data *emif = s->private; - seq_printf(s, "MR4=%d\n", emif->temperature_level); + seq_printf(s, "%d\n", emif->temperature_level); return 0; } -- 1.7.9.5 -- 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 8/9] memory: emif: fix timings initialization issue
From: Oleksandr Dmytryshyn The issue was that only the first timings table was added to the emif platform data at the emif driver registration. All other timings tables was filled with zeros. Now all emif timings table are added to the platform data. Signed-off-by: Oleksandr Dmytryshyn --- drivers/memory/emif.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 32ce601..70f6e0f 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -1462,7 +1462,7 @@ static struct emif_data *__init_or_module get_device_details( if (pd->timings) { temp = devm_kzalloc(dev, size, GFP_KERNEL); if (temp) { - memcpy(temp, pd->timings, sizeof(*pd->timings)); + memcpy(temp, pd->timings, size); pd->timings = temp; } else { dev_warn(dev, "%s:%d: allocation error\n", __func__, -- 1.7.9.5 -- 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/9] memory: emif: Correct the lpmode timeout calculation
The driver tries to round up the specified timeout cycles to next power of 2 value. But this is done wrongly. Correcting this here. Signed-off-by: Lokesh Vutla --- drivers/memory/emif.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 06d31c9..8589aba 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -731,9 +731,9 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) if (timeout < 16) { timeout = 0; } else { - timeout = __fls(timeout) - 3; if (timeout & (timeout - 1)) - timeout++; + timeout <<= 1; + timeout = __fls(timeout) - 3; } switch (lpmode) { -- 1.7.9.5 -- 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 7/9] memory: emif: disable phy_fast_dll_lock
From: Nishanth Menon As per OMAP5 TRM, phy_fast_dll_lock is meant for simulations only. '0' is supposed to be used for normal operations. So, use 0. Signed-off-by: Nishanth Menon --- drivers/memory/emif.h |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index bfe08ba..574fdfb 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h @@ -82,7 +82,7 @@ #define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF /* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */ -#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY0x0E084200 +#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY0x0E084000 #define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS 1 /* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */ -- 1.7.9.5 -- 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/9] memory: emif: handle overflow for timing for LP mode
From: Nishanth Menon In case the custom timings provide values which overflow the maximum possible field value, warn and use maximum permissible value. Signed-off-by: Nishanth Menon --- drivers/memory/emif.c | 36 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 69a480d..27a3ce1 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -714,6 +714,8 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) u32 timeout_perf= EMIF_LP_MODE_TIMEOUT_PERFORMANCE; u32 timeout_pwr = EMIF_LP_MODE_TIMEOUT_POWER; u32 freq_threshold = EMIF_LP_MODE_FREQ_THRESHOLD; + u32 mask; + u8 shift; struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs; @@ -738,27 +740,45 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) switch (lpmode) { case EMIF_LP_MODE_CLOCK_STOP: - pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) | - SR_TIM_MASK | PD_TIM_MASK; + shift = CS_TIM_SHIFT; + mask = CS_TIM_MASK; break; case EMIF_LP_MODE_SELF_REFRESH: /* Workaround for errata i735 */ if (timeout < 6) timeout = 6; - pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) | - CS_TIM_MASK | PD_TIM_MASK; + shift = SR_TIM_SHIFT; + mask = SR_TIM_MASK; break; case EMIF_LP_MODE_PWR_DN: - pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) | - CS_TIM_MASK | SR_TIM_MASK; + shift = PD_TIM_SHIFT; + mask = PD_TIM_MASK; break; case EMIF_LP_MODE_DISABLE: default: - pwr_mgmt_ctrl = CS_TIM_MASK | - PD_TIM_MASK | SR_TIM_MASK; + mask = 0; + shift = 0; + break; + } + /* Round to maximum in case of overflow, BUT warn! */ + if (lpmode != EMIF_LP_MODE_DISABLE && timeout > mask >> shift) { + pr_err("TIMEOUT Overflow - lpmode=%d perf=%d pwr=%d freq=%d\n", + lpmode, + timeout_perf, + timeout_pwr, + freq_threshold); + WARN(1, "timeout=0x%02x greater than 0x%02x. Using max\n", +timeout, mask >> shift); + timeout = mask >> shift; } + /* Setup required timing */ + pwr_mgmt_ctrl = (timeout << shift) & mask; + /* setup a default mask for rest of the modes */ + pwr_mgmt_ctrl |= (SR_TIM_MASK | CS_TIM_MASK | PD_TIM_MASK) & + ~mask; + /* No CS_TIM in EMIF_4D5 */ if (ip_rev == EMIF_4D5) pwr_mgmt_ctrl &= ~CS_TIM_MASK; -- 1.7.9.5 -- 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/9] memory: emif: Handle devices which are not rated for >85C
From: Nishanth Menon As per JESD209-2E specification for LPDDR2, http://www.jedec.org/standards-documents/results/jesd209-2E Table 73, LPDDR2 memories come in two flavors - Standard and Extended. The Standard types can operate from -25C to +85C However, beyond that and upto +105C can only be supported by Extended types. Unfortunately, it seems there is no info in MR0(device info) or MR[1,2](device feature) for run time detection of this capability as far as seen on the spec. Hence, we provide a custom_config flag to be populated by platforms which have these "extended" type memories. For the "Standard" memories, we need to consider MR4 notifications of temperature triggers >85C as equivalent to thermal shutdown events (equivalent to Spec specified thermal shutdown events for "extended" parts). Reported-by: Richard Woodruff Signed-off-by: Nishanth Menon --- drivers/memory/emif.c | 24 include/linux/platform_data/emif_plat.h |1 + 2 files changed, 25 insertions(+) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 27a3ce1..ffbdf9e 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -916,6 +916,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) { u32 old_temp_level; irqreturn_t ret = IRQ_HANDLED; + struct emif_custom_configs *custom_configs; spin_lock_irqsave(&emif_lock, irq_state); old_temp_level = emif->temperature_level; @@ -928,6 +929,29 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) goto out; } + custom_configs = emif->plat_data->custom_configs; + + /* +* IF we detect higher than "nominal rating" from DDR sensor +* on an unsupported DDR part, shutdown system +*/ + if (custom_configs && !(custom_configs->mask & + EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART)) { + if (emif->temperature_level >= SDRAM_TEMP_HIGH_DERATE_REFRESH) { + dev_err(emif->dev, + "%s:NOT Extended temperature capable memory." + "Converting MR4=0x%02x as shutdown event\n", + __func__, emif->temperature_level); + /* +* Temperature far too high - do kernel_power_off() +* from thread context +*/ + emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN; + ret = IRQ_WAKE_THREAD; + goto out; + } + } + if (emif->temperature_level < old_temp_level || emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { /* diff --git a/include/linux/platform_data/emif_plat.h b/include/linux/platform_data/emif_plat.h index 03378ca..5c19a2a 100644 --- a/include/linux/platform_data/emif_plat.h +++ b/include/linux/platform_data/emif_plat.h @@ -40,6 +40,7 @@ /* Custom config requests */ #define EMIF_CUSTOM_CONFIG_LPMODE 0x0001 #define EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL0x0002 +#define EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART 0x0004 #ifndef __ASSEMBLY__ /** -- 1.7.9.5 -- 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/9] memory: emif: use restart if power_off not present when out of spec
From: Nishanth Menon Some machine or kernel variants might have missed implementation of power off handlers. We DONOT want to let the system be in "out of spec" state in this condition. So, WARN and attempt a machine restart in the hopes of clearing the out-of-spec temperature condition. NOTE: This is not the safest option, but safer than leaving the system in unstable conditions. Signed-off-by: Nishanth Menon --- drivers/memory/emif.c |9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index ffbdf9e..625732d 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "emif.h" #include "of_memory.h" @@ -1013,7 +1014,13 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id) if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); - kernel_power_off(); + /* If we have Power OFF ability, use it, else try restarting */ + if (pm_power_off) { + kernel_power_off(); + } else { + WARN(1, "FIXME: NO pm_power_off!!! trying restart\n"); + kernel_restart("SDRAM Over-temp Emergency restart"); + } return IRQ_HANDLED; } -- 1.7.9.5 -- 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 9/9] memory: emif: use default custom config parameter.
From: Ambresh K In-case of low power mode selected and custom parameters are not configured, then use default configuration. Signed-off-by: Ambresh K --- drivers/memory/emif.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 70f6e0f..e58fde4 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -722,9 +722,13 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) if (cust_cfgs && (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE)) { lpmode = cust_cfgs->lpmode; - timeout_perf= cust_cfgs->lpmode_timeout_performance; - timeout_pwr = cust_cfgs->lpmode_timeout_power; - freq_threshold = cust_cfgs->lpmode_freq_threshold; + + if (cust_cfgs->lpmode_timeout_performance) + timeout_perf= cust_cfgs->lpmode_timeout_performance; + if (cust_cfgs->lpmode_timeout_power) + timeout_pwr = cust_cfgs->lpmode_timeout_power; + if (cust_cfgs->lpmode_freq_threshold) + freq_threshold = cust_cfgs->lpmode_freq_threshold; } /* Timeout based on DDR frequency */ -- 1.7.9.5 -- 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
Re: [PATCH 0/9] memory: emif: miscellaneous bug fixes for EMIF driver
Sorry to Spam you in-box. Please discard this message... Thanks Lokesh On Monday 10 December 2012 12:38 PM, a...@dbdp33.itg.ti.com wrote: From: Lokesh Vutla This series resolves a few minor issues for EMIF driver. Tested all the patches on OMAP4-sdp, OMAP5-sevm. Patch : "memory: emif: setup LP settings on freq update" is tested on a local tree, since freq update cannot be tested on mainline. Ambresh K (1): memory: emif: use default custom config parameter. Lokesh Vutla (1): memory: emif: Correct the lpmode timeout calculation Nishanth Menon (5): memory: emif: setup LP settings on freq update memory: emif: handle overflow for timing for LP mode memory: emif: Handle devices which are not rated for >85C memory: emif: use restart if power_off not present when out of spec memory: emif: disable phy_fast_dll_lock Oleksandr Dmytryshyn (1): memory: emif: fix timings initialization issue Severine Glock (1): memory: emif: debugfs: Remove MR4= string print drivers/memory/emif.c | 92 +-- drivers/memory/emif.h |2 +- include/linux/platform_data/emif_plat.h |1 + 3 files changed, 78 insertions(+), 17 deletions(-) -- 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
Re: [PATCH 5/5] OMAPFB: connect ovl managers to all dssdevs
Hi, On Friday 07 December 2012 05:25 PM, Tomi Valkeinen wrote: Commit 5d89bcc341771d95e3a2996218e5949a6627f59e (OMAPDSS: remove initial display code from omapdss) moved setting up the initial overlay, overlay manager, output and display connections from omapdss to omapfb. However, currently omapfb only handles the connection related to the default display, which means that no overlay managers are connected to other displays. This patch changes omapfb to go through all dssdevs, and connect an overlay manager to them. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 38 +++--- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 1df973e..24739fc 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2353,27 +2353,37 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, } static int omapfb_init_connections(struct omapfb2_device *fbdev, - struct omap_dss_device *dssdev) + struct omap_dss_device *def_dssdev) { int i, r; - struct omap_overlay_manager *mgr = NULL; + struct omap_overlay_manager *mgr; - for (i = 0; i < fbdev->num_managers; i++) { - mgr = fbdev->managers[i]; - - if (dssdev->channel == mgr->id) - break; + if (!def_dssdev->output) { + dev_err(fbdev->dev, "no output for the default display\n"); + return -EINVAL; } - if (i == fbdev->num_managers) - return -ENODEV; + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; + struct omap_dss_output *out = dssdev->output; - if (mgr->output) - mgr->unset_output(mgr); + mgr = omap_dss_get_overlay_manager(dssdev->channel); This dssdev->channel reference is something we would want to get rid of eventually, right? At the point omapfb_init_connections() is called, we would have all the omap_dss_devices registered, right? So at this point, omapfb will have an overall view of how the panels need to be connected to DSS. I think we can try to find a manager here for dssdev rather than using dssdev->channel directly. The dssdev's output could connect to a few managers. We would want to chose managers for each dssdev output in such a way that all outputs have a manager. I guess there would be multiple combinations for this, but it would be okay to pick any one of them. I think we would need some recursive or backtracking sort of approach to get a desired combination. We can figure about how to make it work later, but do you agree if this is a right way to get rid of dssdev->channel? Also, we would need to do this for omapdrm separately using it's own encoder/connector entities. Archit - r = mgr->set_output(mgr, dssdev->output); - if (r) - return r; + if (!mgr || !out) + continue; + + if (mgr->output) + mgr->unset_output(mgr); + + mgr->set_output(mgr, out); + } + + mgr = def_dssdev->output->manager; + + if (!mgr) { + dev_err(fbdev->dev, "no ovl manager for the default display\n"); + return -EINVAL; + } for (i = 0; i < fbdev->num_overlays; i++) { struct omap_overlay *ovl = fbdev->overlays[i]; -- 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/1] net: ethernet: davinci_cpdma: Add boundary for rx and tx descriptors
When there is heavy transmission traffic in the CPDMA, then Rx descriptors memory is also utilized as tx desc memory this leads to reduced rx desc memory which leads to poor performance. This patch adds boundary for tx and rx descriptors in bd ram dividing the descriptor memory to ensure that during heavy transmission tx doesn't use rx descriptors. This patch is already applied to davinci_emac driver, since CPSW and davici_dmac uses the same CPDMA, moving the boundry seperation from Davinci EMAC driver to CPDMA driver which was done in the following commit commit 86d8c07ff2448eb4e860e50f34ef6ee78e45c40c Author: Sascha Hauer Date: Tue Jan 3 05:27:47 2012 + net/davinci: do not use all descriptors for tx packets The driver uses a shared pool for both rx and tx descriptors. During open it queues fixed number of 128 descriptors for receive packets. For each received packet it tries to queue another descriptor. If this fails the descriptor is lost for rx. The driver has no limitation on tx descriptors to use, so it can happen during a nmap / ping -f attack that the driver allocates all descriptors for tx and looses all rx descriptors. The driver stops working then. To fix this limit the number of tx descriptors used to half of the descriptors available, the rx path uses the other half. Tested on a custom board using nmap / ping -f to the board from two different hosts. Signed-off-by: Mugunthan V N --- drivers/net/ethernet/ti/davinci_cpdma.c | 20 ++-- drivers/net/ethernet/ti/davinci_emac.c |8 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 4995673..d37f546 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -105,13 +105,13 @@ struct cpdma_ctlr { }; struct cpdma_chan { + struct cpdma_desc __iomem *head, *tail; + void __iomem*hdp, *cp, *rxfree; enum cpdma_statestate; struct cpdma_ctlr *ctlr; int chan_num; spinlock_t lock; - struct cpdma_desc __iomem *head, *tail; int count; - void __iomem*hdp, *cp, *rxfree; u32 mask; cpdma_handler_fnhandler; enum dma_data_direction dir; @@ -217,7 +217,7 @@ desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) } static struct cpdma_desc __iomem * -cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc) +cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx) { unsigned long flags; int index; @@ -225,8 +225,14 @@ cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc) spin_lock_irqsave(&pool->lock, flags); - index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0, - num_desc, 0); + if (is_rx) { + index = bitmap_find_next_zero_area(pool->bitmap, + pool->num_desc/2, 0, num_desc, 0); +} else { + index = bitmap_find_next_zero_area(pool->bitmap, + pool->num_desc, pool->num_desc/2, num_desc, 0); + } + if (index < pool->num_desc) { bitmap_set(pool->bitmap, index, num_desc); desc = pool->iomap + pool->desc_size * index; @@ -660,6 +666,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, unsigned long flags; u32 mode; int ret = 0; + boolis_rx; spin_lock_irqsave(&chan->lock, flags); @@ -668,7 +675,8 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, goto unlock_ret; } - desc = cpdma_desc_alloc(ctlr->pool, 1); + is_rx = (chan->rxfree != 0); + desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx); if (!desc) { chan->stats.desc_alloc_fail++; ret = -ENOMEM; diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index fce89a0..f349273 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -120,7 +120,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; #define EMAC_DEF_TX_CH (0) /* Default 0th channel */ #define EMAC_DEF_RX_CH (0) /* Default 0th channel */ #define EMAC_DEF_RX_NUM_DESC (128) -#define EMAC_DEF_TX_NUM_DESC (128) #define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */ #define EMAC_DEF_MAX_RX_CH (1) /* Max RX