: ARM: OMAP: PM usecounting changes
Subsystems (7)
v6 cover : ARM: OMAP: PM usecounting changes
Hi,
Changes compared to previous version:
- Added patch #1 for fixing a potential race condition within clockdomain code
- Fixed patch #3 (old patch #2) regarding a similar race condition within the voltagedomain code
Tested with OMAP3 beagle, OMAP4460 GP panda, OMAP4430 EMU blaze devices.
Branch available:
git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.6-rc5-pwrdm-changes-v6
-Tero
PATCH v6 1/11 ARM: OMAP: clockdomain: Fix locking on _clkdm_clk_hwmod_enable / disable
Previously the code only acquired spinlock after increasing / decreasing the usecount value, which is wrong. This leaves a small window where a task switch may occur between the check of the usecount and the actual wakeup / sleep of the domain. Fixed by moving the spinlock locking before the usecount access. Left the usecount as atomic_t if someone wants an easy access to the parameter through atomic_read.
--- arch/arm/mach-omap2/clockdomain.c | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/clockdomain.c +11 -4
@@ -914,15 +914,18 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)return -EINVAL ; +spin_lock_irqsave (&clkdm->lock, flags); +/* * For arch's with no autodeps, clkcm_clk_enable * should be called for every clock instance or hwmod that is * enabled, so the clkdm can be force woken up. */ -if ((atomic_inc_return (&clkdm->usecount) >1 ) && autodeps) +if ((atomic_inc_return (&clkdm->usecount) >1 ) && autodeps) { +spin_unlock_irqrestore (&clkdm->lock, flags);return 0 ; + } -spin_lock_irqsave (&clkdm->lock, flags); arch_clkdm->clkdm_clk_enable (clkdm);pwrdm_state_switch (clkdm->pwrdm.ptr);spin_unlock_irqrestore (&clkdm->lock, flags);
@@ -939,15 +942,19 @@ static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)return -EINVAL ; +spin_lock_irqsave (&clkdm->lock, flags); +if (atomic_read (&clkdm->usecount) ==0 ) { +spin_unlock_irqrestore (&clkdm->lock, flags);WARN_ON (1 );/* underflow */ return -ERANGE ; } -if (atomic_dec_return (&clkdm->usecount) >0 ) +if (atomic_dec_return (&clkdm->usecount) >0 ) { +spin_unlock_irqrestore (&clkdm->lock, flags);return 0 ; + } -spin_lock_irqsave (&clkdm->lock, flags); arch_clkdm->clkdm_clk_disable (clkdm);pwrdm_state_switch (clkdm->pwrdm.ptr);spin_unlock_irqrestore (&clkdm->lock, flags);
Signature · 1 line
1.7.4.1
Paul Walmsley
maintainerPATCH v6 1/11 ARM: OMAP: clockdomain: Fix locking on _clkdm_clk_hwmod_enable / disable
Quoted 8 lines · Tero Kristo
Previously the code only acquired spinlock after increasing / decreasing the usecount value, which is wrong. This leaves a small window where a task switch may occur between the check of the usecount and the actual wakeup / sleep of the domain. Fixed by moving the spinlock locking before the usecount access. Left the usecount as
atomic_tif someone wants an easy access to the parameter throughatomic_read.Signed-off-by Tero Kristo <[email protected]>
Thanks, queued for 3.7-rc fixes.
- Paul
Paul Walmsley
maintainerPATCH v6 1/11 ARM: OMAP: clockdomain: Fix locking on _clkdm_clk_hwmod_enable / disable
In reply to Tero KristoQuoted 8 lines · Tero Kristo
Previously the code only acquired spinlock after increasing / decreasing the usecount value, which is wrong. This leaves a small window where a task switch may occur between the check of the usecount and the actual wakeup / sleep of the domain. Fixed by moving the spinlock locking before the usecount access. Left the usecount as
atomic_tif someone wants an easy access to the parameter throughatomic_read.Signed-off-by Tero Kristo <[email protected]>
- Paul
Tony Lindgren
maintainerPATCH v6 1/11 ARM: OMAP: clockdomain: Fix locking on _clkdm_clk_hwmod_enable / disable
Quoted 9 lines · Paul Walmsley
Quoted 7 lines · Tero Kristo
Previously the code only acquired spinlock after increasing / decreasing the usecount value, which is wrong. This leaves a small window where a task switch may occur between the check of the usecount and the actual wakeup / sleep of the domain. Fixed by moving the spinlock locking before the usecount access. Left the usecount as
atomic_tif someone wants an easy access to the parameter throughatomic_read.
Quoted 3 lines
Quoted 1 line
Signed-off-by Tero Kristo <[email protected]>Acked-by Paul Walmsley <[email protected]>
OK I'll apply this into omap-for-v3.7-rc1/fixes-take4.
Regards,
Tony
PATCH v6 2/11 ARM: OMAP3+: voltage/pwrdm/clkdm/clock add recursive usecount tracking
In reply to Tero KristoThis patch fixes the usecount tracking for omap3+, previously the usecount numbers were rather bogus and were not really useful for any purpose. Now usecount numbers track the number of really active clients on each domain. This patch also adds support for usecount tracking on powerdomain level and autoidle flag for clocks that are hardware controlled and should be skipped in usecount calculations.
--- arch/arm/mach-omap2/clkt_iclk.c | 21 ++++++++++++++++++ arch/arm/mach-omap2/clockdomain.c | 16 +++++++++++++- arch/arm/mach-omap2/dpll3xxx.c | 19 ++++++++++++++++ arch/arm/mach-omap2/powerdomain.c | 35 +++++++++++++++++++++++++++++++ arch/arm/mach-omap2/powerdomain.h | 4 +++ arch/arm/plat-omap/clock.c | 6 +++++ arch/arm/plat-omap/include/plat/clock.h | 2 + 7 files changed, 102 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/clkt_iclk.c +21 -0
@@ -21,6 +21,7 @@#include "clock2xxx.h" #include "cm2xxx_3xxx.h" #include "cm-regbits-24xx.h" +#include "clockdomain.h" /* Private functions */
@@ -34,6 +35,16 @@ void omap2_clkt_iclk_allow_idle(struct clk *clk) v =__raw_readl ((__force void __iomem *)r); v |= (1 << clk->enable_bit);__raw_writel (v, (__force void __iomem *)r); + +/* Remove this clock from parent clockdomain usecounts */ +if (clk->usecount && clk->clkdm) +clkdm_clk_disable (clk->clkdm, clk); + +/* +* Mark as autoidle, so we continue to ignore this clock in +* parent clkdm usecount calculations +*/ + clk->autoidle = true; }/* XXX */
@@ -46,6 +57,16 @@ void omap2_clkt_iclk_deny_idle(struct clk *clk) v =__raw_readl ((__force void __iomem *)r); v &= ~(1 << clk->enable_bit);__raw_writel (v, (__force void __iomem *)r); + +/* +* Disable autoidle flag so further clkdm usecounts take this +* clock into account +*/ + clk->autoidle = false; + +/* Add clock back to parent clockdomain usecount */ +if (clk->usecount && clk->clkdm) +clkdm_clk_enable (clk->clkdm, clk); }/* Public data */
arch/arm/mach-omap2/clockdomain.c +15 -1
@@ -910,6 +910,7 @@ bool clkdm_in_hwsup(struct clockdomain *clkdm)static int _clkdm_clk_hwmod_enable (struct clockdomain *clkdm) {unsigned long flags; +int usecount;if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)return -EINVAL ;
@@ -921,12 +922,16 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)* should be called for every clock instance or hwmod that is * enabled, so the clkdm can be force woken up. */ -if ((atomic_inc_return (&clkdm->usecount) >1 ) && autodeps) { + usecount =atomic_inc_return (&clkdm->usecount); + +if (usecount >1 && autodeps) {spin_unlock_irqrestore (&clkdm->lock, flags);return 0 ; } arch_clkdm->clkdm_clk_enable (clkdm); +if (usecount ==1 ) +pwrdm_clkdm_enable (clkdm->pwrdm.ptr);pwrdm_state_switch (clkdm->pwrdm.ptr);spin_unlock_irqrestore (&clkdm->lock, flags);
@@ -956,6 +961,7 @@ static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm) } arch_clkdm->clkdm_clk_disable (clkdm); +pwrdm_clkdm_disable (clkdm->pwrdm.ptr);pwrdm_state_switch (clkdm->pwrdm.ptr);spin_unlock_irqrestore (&clkdm->lock, flags);
@@ -988,6 +994,10 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)if (!clk)return -EINVAL ; +/* If autoidle clock, do not update clkdm usecounts */ +if (clk->autoidle) +return 0 ; +return _clkdm_clk_hwmod_enable (clkdm); }
@@ -1014,6 +1024,10 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)if (!clk)return -EINVAL ; +/* If autoidle clock, do not update clkdm usecounts */ +if (clk->autoidle) +return 0 ; +return _clkdm_clk_hwmod_disable (clkdm); }
arch/arm/mach-omap2/dpll3xxx.c +19 -0
@@ -34,6 +34,7 @@#include "clock.h" #include "cm2xxx_3xxx.h" #include "cm-regbits-34xx.h" +#include "clockdomain.h" /* CM_AUTOIDLE_PLL*.AUTO_* bit values */ #define DPLL_AUTOIDLE_DISABLE 0x0
@@ -571,6 +572,15 @@ void omap3_dpll_allow_idle(struct clk *clk) v |=DPLL_AUTOIDLE_LOW_POWER_STOP <<__ffs (dd->autoidle_mask);__raw_writel (v, dd->autoidle_reg); +/* Remove this clock from parent clockdomain usecounts */ +if (clk->usecount && clk->clkdm) +clkdm_clk_disable (clk->clkdm, clk); + +/* +* Mark as autoidle, so we continue to ignore this clock in +* parent clkdm usecount calculations +*/ + clk->autoidle = true; }/**
@@ -600,6 +610,15 @@ void omap3_dpll_deny_idle(struct clk *clk) v |=DPLL_AUTOIDLE_DISABLE <<__ffs (dd->autoidle_mask);__raw_writel (v, dd->autoidle_reg); +/* +* Disable autoidle flag so further clkdm usecounts take this +* clock into account +*/ + clk->autoidle = false; + +/* Add clock back to parent clockdomain usecount */ +if (clk->usecount && clk->clkdm) +clkdm_clk_enable (clk->clkdm, clk); }/* Clock control for DPLL outputs */
arch/arm/mach-omap2/powerdomain.c +35 -0
@@ -1466,6 +1466,41 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)return ret; } +/** +* pwrdm_clkdm_enable - increment powerdomain usecount +* @pwrdm: struct powerdomain * +* +* Increases the usecount for a powerdomain. Called from clockdomain +* code once a clockdomain becomes active. +*/ +void pwrdm_clkdm_enable (struct powerdomain *pwrdm) +{ +if (!pwrdm) +return ; + +atomic_inc (&pwrdm->usecount); +} + +/** +* pwrdm_clkdm_disable - decrease powerdomain usecount +* @pwrdm: struct powerdomain * +* +* Decreases the usecount for a powerdomain. Called from clockdomain +* code once a clockdomain usecount reaches zero, i.e. it is ready to +* idle. +*/ +void pwrdm_clkdm_disable (struct powerdomain *pwrdm) +{ +int val; + +if (!pwrdm) +return ; + + val =atomic_dec_return (&pwrdm->usecount); + +WARN_ON (val <0 ); +} +int pwrdm_pre_transition (struct powerdomain *pwrdm) {if (pwrdm)
arch/arm/mach-omap2/powerdomain.h +4 -0
@@ -92,6 +92,9 @@ int pwrdm_state_switch(struct powerdomain *pwrdm);int pwrdm_pre_transition (struct powerdomain *pwrdm);int pwrdm_post_transition (struct powerdomain *pwrdm); +void pwrdm_clkdm_enable (struct powerdomain *pwrdm); +void pwrdm_clkdm_disable (struct powerdomain *pwrdm); +int pwrdm_get_context_loss_count (struct powerdomain *pwrdm);bool pwrdm_can_ever_lose_context (struct powerdomain *pwrdm);
@@ -209,6 +212,7 @@ struct powerdomain {unsigned state_counter[PWRDM_MAX_FUNC_PWRSTS ];unsigned ret_logic_off_counter;unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS ]; +atomic_t usecount;const u8 pwrstctrl_offs;const u8 pwrstst_offs;
arch/arm/plat-omap/clock.c +6 -0
@@ -282,6 +282,12 @@ int clk_register(struct clk *clk)list_add (&clk->sibling, &root_clks);list_add (&clk->node, &clocks); +/* +* If clock has no ops, it is handled by hardware and thus will +* idle automatically +*/ +if (clk->ops == &clkops_null) + clk->autoidle = true;if (clk->init) clk->init (clk);mutex_unlock (&clocks_mutex);
arch/arm/plat-omap/include/plat/clock.h +2 -0
@@ -206,6 +206,7 @@ struct dpll_data {* @init: fn ptr to do clock-specific initialization * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg) * @usecount: number of users that have requested this clock to be enabled +* @autoidle: indicates hardware controlled clock (not used in domain usecounts) * @fixed_div: when > 0, this clock's rate is its parent's rate / @fixed_div * @flags: see "struct clk.flags possibilities" above * @clksel_reg: for clksel clks, register va containing src/divisor select
@@ -252,6 +253,7 @@ struct clk {void (*init)(struct clk *);u8 enable_bit;s8 usecount; +bool autoidle;u8 fixed_div;u8 flags;#ifdef CONFIG_ARCH_OMAP2PLUS
Signature · 1 line
1.7.4.1
PATCH v6 3/11 ARM: OMAP3+: voltage: add support for voltagedomain usecounts
In reply to Tero KristoThese are updated based on powerdomain usecounts. Also added support for voltdm->sleep and voltdm->wakeup calls that will be invoked once voltagedomain enters sleep or wakes up based on usecount numbers. These will be used for controlling voltage scaling functionality.
--- arch/arm/mach-omap2/powerdomain.c | 17 +++++++++- arch/arm/mach-omap2/voltage.c | 65 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/voltage.h | 13 +++++++ 3 files changed, 94 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/powerdomain.c +16 -1
@@ -1475,10 +1475,17 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)*/ void pwrdm_clkdm_enable (struct powerdomain *pwrdm) { +unsigned long flags; +if (!pwrdm)return ; -atomic_inc (&pwrdm->usecount); +spin_lock_irqsave (&pwrdm->lock, flags); + +if (atomic_inc_return (&pwrdm->usecount) ==1 ) +voltdm_pwrdm_enable (pwrdm->voltdm.ptr); + +spin_unlock_irqrestore (&pwrdm->lock, flags); }/**
@@ -1492,12 +1499,20 @@ void pwrdm_clkdm_enable(struct powerdomain *pwrdm)void pwrdm_clkdm_disable (struct powerdomain *pwrdm) {int val; +unsigned long flags;if (!pwrdm)return ; +spin_lock_irqsave (&pwrdm->lock, flags); + val =atomic_dec_return (&pwrdm->usecount); +if (!val) +voltdm_pwrdm_disable (pwrdm->voltdm.ptr); + +spin_unlock_irqrestore (&pwrdm->lock, flags); +WARN_ON (val <0 ); }
arch/arm/mach-omap2/voltage.c +65 -0
77 lines not on this page · raw message
arch/arm/mach-omap2/voltage.h +13 -0
@@ -15,6 +15,7 @@#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H#include <linux/err.h> +#include <linux/spinlock.h> #include <plat/voltage.h>
@@ -56,10 +57,14 @@ struct omap_vfsm_instance {* @pwrdm_list: list_head linking all powerdomains in this voltagedomain * @vc: pointer to VC channel associated with this voltagedomain * @vp: pointer to VP associated with this voltagedomain +* @usecount: number of users for this voltagedomain +* @target_state: calculated target state for the children of this domain * @read: read a VC/VP register * @write: write a VC/VP register * @read: read-modify-write a VC/VP register * @sys_clk: system clock name/frequency, used for various timing calculations +* @sleep: function to call once the domain enters idle +* @wakeup: function to call once the domain wakes up from idle * @scale: function used to scale the voltage of the voltagedomain * @nominal_volt: current nominal voltage for this voltage domain * @volt_data: voltage table having the distinct voltages supported
@@ -75,6 +80,9 @@ struct voltagedomain {struct omap_vp_instance *vp;struct omap_voltdm_pmic *pmic; +atomic_t usecount; +u8 target_state; +/* VC/VP register access functions: SoC specific */ u32 (*read) (u8 offset);void (*write) (u32 val,u8 offset);
@@ -85,11 +93,14 @@ struct voltagedomain {u32 rate; } sys_clk; +void (*sleep) (struct voltagedomain *voltdm); +void (*wakeup) (struct voltagedomain *voltdm);int (*scale) (struct voltagedomain *voltdm,unsigned long target_volt);u32 nominal_volt;struct omap_volt_data *volt_data; +spinlock_t lock; };/**
@@ -145,6 +156,8 @@ extern void omap44xx_voltagedomains_init(void);struct voltagedomain *voltdm_lookup (const char *name);void voltdm_init (struct voltagedomain **voltdm_list);int voltdm_add_pwrdm (struct voltagedomain *voltdm,struct powerdomain *pwrdm); +void voltdm_pwrdm_enable (struct voltagedomain *voltdm); +void voltdm_pwrdm_disable (struct voltagedomain *voltdm);int voltdm_for_each (int (*fn)(struct voltagedomain *voltdm,void *user),void *user); int voltdm_for_each_pwrdm(struct voltagedomain *voltdm,
Signature · 1 line
1.7.4.1
PATCH v6 4/11 ARM: OMAP3: add manual control for mpu / core pwrdm usecounting
In reply to Tero Kristompu / core powerdomain usecounts are now statically increased by 1 during MPU activity. This allows the domains to reflect actual usage, and will allow the usecount to reach 0 just before all CPUs are ready to idle. Proper powerdomain usecounts are propageted to voltagedomain level also, and will allow vc callbacks to be triggered at right point of time.
--- arch/arm/mach-omap2/common.h | 6 ++ arch/arm/mach-omap2/omap-mpuss-lowpower.c | 72 ++++++++++++++++++++++++++++- arch/arm/mach-omap2/omap-smp.c | 2 + arch/arm/mach-omap2/pm34xx.c | 21 ++++++++ 4 files changed, 100 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/common.h +6 -0
@@ -292,6 +292,8 @@ 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 u32 omap4_mpuss_read_prev_context_state (void ); +extern void omap4_pm_cpu_online (void ); +extern void omap4_pm_cpu_offline (void );#else static inline int omap4_enter_lowpower (unsigned int cpu,unsigned int power_state)
@@ -323,6 +325,10 @@ static inline u32 omap4_mpuss_read_prev_context_state(void) {return 0 ; } + +static inline void omap4_pm_cpu_online (void ) { } + +static inline void omap4_pm_cpu_offline (void ) { }#endif struct omap_sdrc_params ;
arch/arm/mach-omap2/omap-mpuss-lowpower.c +71 -1
117 lines not on this page · raw message
arch/arm/mach-omap2/omap-smp.c +2 -0
@@ -71,6 +71,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)*/ gic_secondary_init (0 ); +omap4_pm_cpu_online (); +/* * Synchronise with the boot thread. */
arch/arm/mach-omap2/pm34xx.c +21 -0
@@ -294,6 +294,14 @@ void omap_sram_idle(void)omap3_intc_prepare_idle ();/* +* CPU going offline, update pwrdm counters. Core pwrdm +* count is decreased as MPU is using SDRAM which resides +* under core pwrdm. +*/ +pwrdm_clkdm_disable (mpu_pwrdm); +pwrdm_clkdm_disable (core_pwrdm); + +/* * On EMU/HS devices ROM code restores a SRDC value * from scratchpad which has automatic self refresh on timeout * of AUTO_CNT = 1 enabled. This takes care of erratum ID i443.
@@ -324,6 +332,12 @@ void omap_sram_idle(void) core_next_state == PWRDM_FUNC_PWRST_OFF)sdrc_write_reg (sdrc_pwr,SDRC_POWER ); +/* +* CPU is coming back online, increase pwrdm usecounts +*/ +pwrdm_clkdm_enable (mpu_pwrdm); +pwrdm_clkdm_enable (core_pwrdm); +/* CORE */ if (core_next_state <PWRDM_FUNC_PWRST_ON ) { core_prev_state =pwrdm_read_prev_fpwrst (core_pwrdm);
@@ -718,6 +732,13 @@ int __init omap3_pm_init(void) omap_pm_suspend = omap3_pm_suspend;#endif +/* +* CPU online, increase pwrdm usecounts for MPU and CORE domains. +* MPU is using memory subsystem which resides in CORE domain. +*/ +pwrdm_clkdm_enable (mpu_pwrdm); +pwrdm_clkdm_enable (core_pwrdm); + arm_pm_idle = omap3_pm_idle;omap3_idle_init ();
Signature · 1 line
1.7.4.1
PATCH v6 5/11 ARM: OMAP3: set autoidle flag for sdrc_ick
In reply to Tero Kristosdrc_ick doesn't have autoidle flag on HW, but is always automatically idled. Thus mark the autoidle flag statically as true for it to reflect hardware behavior. The clock will no longer show as active in usecount dumps and will allow the voltdm->sleep / wakeup calls to work properly.
--- arch/arm/mach-omap2/clock3xxx_data.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/clock3xxx_data.c +1 -0
@@ -1739,6 +1739,7 @@ static struct clk sdrc_ick = { .flags = ENABLE_ON_INIT, .clkdm_name = "core_l3_clkdm", .recalc = &followparent_recalc, + .autoidle = true, };static struct clk gpmc_fck = {
Signature · 1 line
1.7.4.1
PATCH v6 6/11 ARM: OMAP: clockdomain: add support for preventing autodep delete
In reply to Tero KristoSome clockdomains bug out if their autodeps are deleted before idle. This happens namely with OMAP3 PER domain, it will bug out if it doesn't have wakedeps enabled when it enters off-mode. This patch adds support for new flag 'CLKDM_NO_AUTODEP_DISABLE' which does this.
--- arch/arm/mach-omap2/clockdomain.c | 3 +++ arch/arm/mach-omap2/clockdomain.h | 4 ++++ 2 files changed, 7 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/clockdomain.c +3 -0
@@ -201,6 +201,9 @@ void _clkdm_del_autodeps(struct clockdomain *clkdm)if (!autodeps || clkdm->flags &CLKDM_NO_AUTODEPS )return ; +if (clkdm->flags &CLKDM_NO_AUTODEP_DISABLE ) +return ; +for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {if (IS_ERR (autodep->clkdm.ptr))continue ;
arch/arm/mach-omap2/clockdomain.h +4 -0
@@ -34,6 +34,9 @@* CLKDM_ACTIVE_WITH_MPU: The PRCM guarantees that this clockdomain is * active whenever the MPU is active. True for interconnects and * the WKUP clockdomains. +* CLKDM_NO_AUTODEP_DISABLE: Prevent clockdomain code from deleting autodeps. +* Needed for PER domain on omap3, as it will bug out with off-mode if +* wakedeps are removed. */ #define CLKDM_CAN_FORCE_SLEEP (1 << 0)#define CLKDM_CAN_FORCE_WAKEUP (1 << 1)
@@ -41,6 +44,7 @@#define CLKDM_CAN_DISABLE_AUTO (1 << 3)#define CLKDM_NO_AUTODEPS (1 << 4)#define CLKDM_ACTIVE_WITH_MPU (1 << 5) +#define CLKDM_NO_AUTODEP_DISABLE (1 << 6)#define CLKDM_CAN_HWSUP (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)#define CLKDM_CAN_SWSUP (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
Signature · 1 line
1.7.4.1
PATCH v6 7/11 ARM: OMAP3: do not delete per_clkdm autodeps during idle
In reply to Tero KristoPreviously, PER clock domain was always enabled, as the usecounts for this domain incorrectly always showed positive value. On HW level though, the domain enters idle as it is set in HW supervised mode. Now, when the usecounts reflect real values, PER domain will be put to HWSUP sleep mode, which means its autodeps are deleted. Removing wakedeps for PER domain will cause multiple problems. First of all, coming back from idle, PER domain remains idle as the wakedeps have been disabled for the domain, and this causes a crash with the GPIO code, as the resume code attempts to access domain which is not active. Just enabling the interface clocks for the GPIO does not help, as they are autoidled and don't bring the domain out of idle. Secondly, there are multiple erratas for omap3, which say that the wakedeps should be enabled for the PER domain, see e.g. errata i582 for omap3630.
--- arch/arm/mach-omap2/clockdomains3xxx_data.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/clockdomains3xxx_data.c +1 -1
@@ -370,7 +370,7 @@ static struct clockdomain usbhost_am35x_clkdm = {static struct clockdomain per_clkdm = { .name ="per_clkdm" , .pwrdm = { .name ="per_pwrdm" }, - .flags =CLKDM_CAN_HWSUP_SWSUP , + .flags =CLKDM_CAN_HWSUP_SWSUP |CLKDM_NO_AUTODEP_DISABLE , .dep_bit =OMAP3430_EN_PER_SHIFT , .wkdep_srcs = per_wkdeps, .sleepdep_srcs = per_sleepdeps,
Signature · 1 line
1.7.4.1
PATCH v6 8/11 ARM: OMAP4: clock data: set autoidle flag for dss_fck
In reply to Tero Kristodss_fck is currently being used improperly within the hwmod database as an interface clock for DSS hwmods. This causes the dss_fck to be enabled even if the dss powerdomain itself is idle, resulting in wrong data within the powerdomain usecounts. Marked dss_fck as autoidle which makes the clock to disappear from usecounts for now. This patch can be reverted once the interface clocks for DSS hwmods have been properly fixed.
--- arch/arm/mach-omap2/clock44xx_data.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/clock44xx_data.c +1 -0
@@ -1408,6 +1408,7 @@ static struct clk dss_fck = { .clkdm_name = "l3_dss_clkdm", .parent = &l3_div_ck, .recalc = &followparent_recalc, + .autoidle = true, };static struct clk efuse_ctrl_cust_fck = {
Signature · 1 line
1.7.4.1
PATCH v6 9/11 ARM: OMAP4: hwmod: add support for hwmod autoidle flag
In reply to Tero KristoIf a hwmod is in HWAUTO mode, it will idle automatically and should not be accounted for in the clkdm / pwrdm usecounts. Thus, flag modules in such mode as autoidle during init, and ignore these in subsequent usecount calculations.
--- arch/arm/mach-omap2/clockdomain.c | 6 ++++++ arch/arm/mach-omap2/omap_hwmod.c | 3 +++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 ++ 3 files changed, 11 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/clockdomain.c +6 -0
@@ -1063,6 +1063,9 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)if (!oh)return -EINVAL ; +if (oh->flags &HWMOD_AUTOIDLE ) +return 0 ; +return _clkdm_clk_hwmod_enable (clkdm); }
@@ -1094,6 +1097,9 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)if (!oh)return -EINVAL ; +if (oh->flags &HWMOD_AUTOIDLE ) +return 0 ; +return _clkdm_clk_hwmod_disable (clkdm); }
arch/arm/mach-omap2/omap_hwmod.c +3 -0
@@ -2377,6 +2377,9 @@ static int __init _register(struct omap_hwmod *oh)INIT_LIST_HEAD (&oh->slave_ports);spin_lock_init (&oh->_lock); +if (cpu_is_omap44xx () && oh->prcm.omap4.modulemode ==MODULEMODE_HWCTRL ) + oh->flags |=HWMOD_AUTOIDLE ; + oh->_state = _HWMOD_STATE_REGISTERED;/*
arch/arm/plat-omap/include/plat/omap_hwmod.h +2 -0
@@ -440,6 +440,7 @@ struct omap_hwmod_omap4_prcm {* in order to complete the reset. Optional clocks will be disabled * again after the reset. * HWMOD_16BIT_REG: Module has 16bit registers +* HWMOD_AUTOIDLE: Module is controlled automatically by hardware */ #define HWMOD_SWSUP_SIDLE (1 << 0)#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -450,6 +451,7 @@ struct omap_hwmod_omap4_prcm {#define HWMOD_NO_IDLEST (1 << 6)#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7)#define HWMOD_16BIT_REG (1 << 8) +#define HWMOD_AUTOIDLE (1 << 9)/* * omap_hwmod._int_flags definitions
Signature · 1 line
1.7.4.1
PATCH v6 10/11 ARM: OMAP4: hwmod data: set mpu hwmod modulemode to hwauto
In reply to Tero KristoThis makes sure it is handled as autoidle type by the usecounting.
--- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +1 -0
@@ -2492,6 +2492,7 @@ static struct omap_hwmod omap44xx_mpu_hwmod = { .omap4 = { .clkctrl_offs = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET, .context_offs = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET, + .modulemode = MODULEMODE_HWCTRL, }, }, };
Signature · 1 line
1.7.4.1
PATCH v6 11/11 ARM: OMAP4: clock data: flag hw controlled clocks as autoidle
In reply to Tero KristoThis makes sure these clocks are ignored by the clkdm / pwrdm usecounting.
--- arch/arm/mach-omap2/clock44xx_data.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/clock44xx_data.c +4 -1
@@ -3356,8 +3356,11 @@ int __init omap4xxx_clk_init(void)*/ for (c = omap44xx_clks; c < omap44xx_clks +ARRAY_SIZE (omap44xx_clks); - c++) + c++) { +if (c->lk.clk->enable_bit ==OMAP4430_MODULEMODE_HWCTRL ) + c->lk.clk->autoidle = true;clk_preinit (c->lk.clk); + }for (c = omap44xx_clks; c < omap44xx_clks +ARRAY_SIZE (omap44xx_clks); c++)
Signature · 1 line
1.7.4.1