Skip to contentSkip to conversation

ARM: OMAP: PM usecounting changes

PATCH Superseded Tero Kristo 3 participants 18 messages Sep 25, 2012 – Sep 26, 2012

Subsystems (7)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v5 cover ARM: OMAP: PM usecounting changes

Hi,

Changes compared to previous version:

- Fixed OMAP4 support (patches 7-10)
- Dropped debugging support from this set for now
- Rebased on top of 3.6-rc5 + func-pwrst + omap4-ret code (omap4 support easier to test with these)
- Patch #1:
* dropped clkdm_usecount_inc / clkdm_usecount_dec APIs
* clkdm_clk_enable / disable are used now instead
* some code ordering changed for the new setup to work properly
* changed BUG_ON calls to WARN_ON
- Patch #2:
* added spinlock for protecting voltdm callbacks
* pwrdm lock extended to protect pwrdm callbacks
- Patch #3:
* dropped generic API call for the cpu pwrdm idle / wakeup
* instead use pwrdm_clkdm_enable / disable calls directly from PM code
* omap4 support fixed to work properly with SMP, added omap4 specific CPU pwrdm idle / wakeup calls for this purpose
- Patch #4:
* no changes
* added 'Reviewed-by' tag for Rajendra
- Patch #5:
* no changes, just rebase
- Patch #6:
* no changes

Tested with OMAP3 beagle, omap4460 GP panda + omap4430 EMU blaze boards.

I will be posting new versions for the voltdm fixes + auto retention + panda board tps6236x support code later on today, which are based on top of this set.

Branch also available here:

git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.6-rc5-pwrdm-changes-v5

-Tero

#1 lore raw

PATCH v5 1/10 ARM: OMAP3+: voltage/pwrdm/clkdm/clock add recursive usecount tracking

This 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.

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/clkt_iclk.c         |   21 ++++++++++++++++++
 arch/arm/mach-omap2/clockdomain.c       |   15 ++++++++++++-
 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, 101 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/clkt_iclk.c +21 -0
index 3d43fba..1afc599 100644
@@ -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 +14 -1
index 8664f5a..8c8518c 100644
@@ -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;
@@ -919,11 +920,14 @@ 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)
 		return 0;
 
 	spin_lock_irqsave(&clkdm->lock, flags);
 	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);
 
@@ -949,6 +953,7 @@ static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
 
 	spin_lock_irqsave(&clkdm->lock, flags);
 	arch_clkdm->clkdm_clk_disable(clkdm);
+	pwrdm_clkdm_disable(clkdm->pwrdm.ptr);
 	pwrdm_state_switch(clkdm->pwrdm.ptr);
 	spin_unlock_irqrestore(&clkdm->lock, flags);
 
@@ -981,6 +986,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);
 }
 
@@ -1007,6 +1016,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
index b9c8d2f..da660d2 100644
@@ -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
index d6daa81..ba49029 100644
@@ -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
index dcd2315..1bad255 100644
@@ -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
index 706b7e2..d657d39 100644
@@ -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
index 656b986..3b5acea 100644
@@ -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
#2 lore raw

PATCH v5 2/10 ARM: OMAP3+: voltage: add support for voltagedomain usecounts

In reply to Tero Kristo

These 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.

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/powerdomain.c |   17 +++++++++-
 arch/arm/mach-omap2/voltage.c     |   62 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/voltage.h     |   13 ++++++++
 3 files changed, 91 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/powerdomain.c +14 -1
index ba49029..ca54aec 100644
@@ -1475,10 +1477,16 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
  */
 void pwrdm_clkdm_enable(struct powerdomain *pwrdm)
 {
+	unsigned long flags;
+
 	if (!pwrdm)
 		return;
 
-	atomic_inc(&pwrdm->usecount);
+	if (atomic_inc_return(&pwrdm->usecount) == 1) {
+		spin_lock_irqsave(&pwrdm->lock, flags);
+		voltdm_pwrdm_enable(pwrdm->voltdm.ptr);
+		spin_unlock_irqrestore(&pwrdm->lock, flags);
+	}
 }
 
 /**
@@ -1492,12 +1500,19 @@ void pwrdm_clkdm_enable(struct powerdomain *pwrdm)
 void pwrdm_clkdm_disable(struct powerdomain *pwrdm)
 {
 	int val;
+	unsigned long flags;
 
 	if (!pwrdm)
 		return;
 
 	val = atomic_dec_return(&pwrdm->usecount);
 
+	if (!val) {
+		spin_lock_irqsave(&pwrdm->lock, flags);
+		voltdm_pwrdm_disable(pwrdm->voltdm.ptr);
+		spin_unlock_irqrestore(&pwrdm->lock, flags);
+	}
+
 	WARN_ON(val < 0);
 }
 
arch/arm/mach-omap2/voltage.c +62 -0

74 lines not on this page · raw message

arch/arm/mach-omap2/voltage.h +13 -0
index 0ac2caf..7f4f99d 100644
@@ -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
#3 lore raw

PATCH v5 2/10 ARM: OMAP3+: voltage: add support for voltagedomain usecounts

Quoted 9 lines · Tero Kristo
arch/arm/mach-omap2/powerdomain.c +1 -0
index ba49029..ca54aec 100644
@@ -1475,10 +1477,16 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
  */
 void pwrdm_clkdm_enable(struct powerdomain *pwrdm)
 {
+	unsigned long flags;

arch/arm/mach-omap2/powerdomain.c int pwrdm_state_switch(struct powerdomain *pwrdm) · line 1489

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +6 -1
+
 	if (!pwrdm)
 		return;
 
-	atomic_inc(&pwrdm->usecount);
+	if (atomic_inc_return(&pwrdm->usecount) == 1) {
+		spin_lock_irqsave(&pwrdm->lock, flags);
+		voltdm_pwrdm_enable(pwrdm->voltdm.ptr);
+		spin_unlock_irqrestore(&pwrdm->lock, flags);
+	}

This looks like the classic "I like atomic types because they have magic properties" brain-deadness.

What would happen to users of this if you had this sequence:

pwrdm->usecount starts off as 1.

Thread0 Thread1
atomic_inc_return() (returns 1)
atomic_inc_return() (returns 2) starts using stuff in power domain
spin_lock_irqsave()
voltdm_pwrdm_enable()
spin_unlock_irqrestore()

?

#4 lore raw

PATCH v5 2/10 ARM: OMAP3+: voltage: add support for voltagedomain usecounts

Quoted 14 lines · Russell King - ARM Linux
Quoted 13 lines · Tero Kristo
arch/arm/mach-omap2/powerdomain.c +2 -0
index ba49029..ca54aec 100644
@@ -1475,10 +1477,16 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
  */
 void pwrdm_clkdm_enable(struct powerdomain *pwrdm)
 {
+	unsigned long flags;
+
 	if (!pwrdm)
 		return;
 
Quoted 9 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_state_switch(struct powerdomain *pwrdm) · line 1489

Quoted 6 lines
arch/arm/mach-omap2/powerdomain.c +5 -1
-	atomic_inc(&pwrdm->usecount);
+	if (atomic_inc_return(&pwrdm->usecount) == 1) {
+		spin_lock_irqsave(&pwrdm->lock, flags);
+		voltdm_pwrdm_enable(pwrdm->voltdm.ptr);
+		spin_unlock_irqrestore(&pwrdm->lock, flags);
+	}

This looks like the classic "I like atomic types because they have magic properties" brain-deadness.

Hi Russell,

Thats a good catch, I was actually thinking about this sequence myself also, but decided to leave it as is here due to similarity with the existing code in mach-omap2/clockdomain.c, see e.g. _clkdm_clk_hwmod_enable. Maybe those parts should be fixed also...?

Quoted 13 lines

What would happen to users of this if you had this sequence:

pwrdm->usecount starts off as 1.

Thread0 Thread1
atomic_inc_return() (returns 1)
atomic_inc_return() (returns 2) starts using stuff in power domain
spin_lock_irqsave()
voltdm_pwrdm_enable()
spin_unlock_irqrestore()

Quoted 1 line

?

That as such wouldn't break anything, as the callback isn't doing anything too critical, but yes, for the sequencing of events it is bad. The alternate implementation I was thinking was to drop the atomic_t and just use an int for the usecount, and protect the usecount also with the spinlock. However, there might be some performance issues if this is done (but I think it is actually better than having some rather mysterious bugs instead.)

-Tero

#5 lore raw

PATCH v5 3/10 ARM: OMAP3: add manual control for mpu / core pwrdm usecounting

In reply to Tero Kristo

mpu / 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.

Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 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
index 6ea837a..a445a02 100644
@@ -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
index b9738e2..f296e35 100644
@@ -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
index 5b6505f..7a423f7 100644
@@ -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
#6 lore raw

PATCH v5 4/10 ARM: OMAP3: set autoidle flag for sdrc_ick

In reply to Tero Kristo

sdrc_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
index 83bed9a..1ddc7fc 100644
@@ -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
#7 lore raw

PATCH v5 5/10 ARM: OMAP: clockdomain: add support for preventing autodep delete

In reply to Tero Kristo

Some 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
index 8c8518c..2fa433a 100644
@@ -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
index 5601dc1..9b8733e 100644
@@ -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
#8 lore raw

PATCH v5 6/10 ARM: OMAP3: do not delete per_clkdm autodeps during idle

In reply to Tero Kristo

Previously, 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
index 56089c4..3b3c524 100644
@@ -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
#9 lore raw

PATCH v5 7/10 ARM: OMAP4: clock data: set autoidle flag for dss_fck

In reply to Tero Kristo

dss_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
index d7f55e4..95834d7 100644
@@ -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
#10 lore raw

PATCH v5 8/10 ARM: OMAP4: hwmod: add support for hwmod autoidle flag

In reply to Tero Kristo

If 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
index 2fa433a..0ee7d09a 100644
@@ -1055,6 +1055,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);
 }
 
@@ -1086,6 +1089,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
index f826917..6807b02 100644
@@ -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
index 0f840a9..36130f9 100644
@@ -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
#11 lore raw

PATCH v5 9/10 ARM: OMAP4: hwmod data: set mpu hwmod modulemode to hwauto

In reply to Tero Kristo

This 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
index 2d13b33..367de25 100644
@@ -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
#12 lore raw

PATCH v5 10/10 ARM: OMAP4: clock data: flag hw controlled clocks as autoidle

In reply to Tero Kristo

This 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
index 95834d7..d2fb4e8 100644
@@ -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
#13 lore raw

v5 cover ARM: OMAP: PM usecounting changes

In reply to Tero Kristo

Hi Tero,

Quoted 3 lines · Tero Kristo

Hi,

Changes compared to previous version:

Did you get a chance to look at the issue I reported about autodeps?
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg72876.html

regards,
Rajendra

Quoted 45 lines

- Fixed OMAP4 support (patches 7-10)
- Dropped debugging support from this set for now
- Rebased on top of 3.6-rc5 + func-pwrst + omap4-ret code (omap4 support easier to test with these)
- Patch #1:
* dropped clkdm_usecount_inc / clkdm_usecount_dec APIs
* clkdm_clk_enable / disable are used now instead
* some code ordering changed for the new setup to work properly
* changed BUG_ON calls to WARN_ON
- Patch #2:
* added spinlock for protecting voltdm callbacks
* pwrdm lock extended to protect pwrdm callbacks
- Patch #3:
* dropped generic API call for the cpu pwrdm idle / wakeup
* instead use pwrdm_clkdm_enable / disable calls directly from PM code
* omap4 support fixed to work properly with SMP, added omap4 specific CPU pwrdm idle / wakeup calls for this purpose
- Patch #4:
* no changes
* added 'Reviewed-by' tag for Rajendra
- Patch #5:
* no changes, just rebase
- Patch #6:
* no changes

Tested with OMAP3 beagle, omap4460 GP panda + omap4430 EMU blaze boards.

I will be posting new versions for the voltdm fixes + auto retention + panda board tps6236x support code later on today, which are based on top of this set.

Branch also available here:

git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.6-rc5-pwrdm-changes-v5

-Tero

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#14 lore raw

v5 cover ARM: OMAP: PM usecounting changes

Quoted 9 lines · Rajendra Nayak

Hi Tero,

Quoted 3 lines · Tero Kristo

Hi,

Changes compared to previous version:

Did you get a chance to look at the issue I reported about autodeps?
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg72876.html

Not really, I didn't think that bug report was meant for me, I kind of thought it only happened with your set. But now looking at your email in detail, I guess you are saying there is a bug in this code (the one that touches iclk stuff), which causes the USB / DSS domains to follow MPU/CORE, is that right?

-Tero

Quoted 50 lines

regards,
Rajendra

Quoted 45 lines

- Fixed OMAP4 support (patches 7-10)
- Dropped debugging support from this set for now
- Rebased on top of 3.6-rc5 + func-pwrst + omap4-ret code (omap4 support easier to test with these)
- Patch #1:
* dropped clkdm_usecount_inc / clkdm_usecount_dec APIs
* clkdm_clk_enable / disable are used now instead
* some code ordering changed for the new setup to work properly
* changed BUG_ON calls to WARN_ON
- Patch #2:
* added spinlock for protecting voltdm callbacks
* pwrdm lock extended to protect pwrdm callbacks
- Patch #3:
* dropped generic API call for the cpu pwrdm idle / wakeup
* instead use pwrdm_clkdm_enable / disable calls directly from PM code
* omap4 support fixed to work properly with SMP, added omap4 specific CPU pwrdm idle / wakeup calls for this purpose
- Patch #4:
* no changes
* added 'Reviewed-by' tag for Rajendra
- Patch #5:
* no changes, just rebase
- Patch #6:
* no changes

Tested with OMAP3 beagle, omap4460 GP panda + omap4430 EMU blaze boards.

I will be posting new versions for the voltdm fixes + auto retention + panda board tps6236x support code later on today, which are based on top of this set.

Branch also available here:

git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.6-rc5-pwrdm-changes-v5

-Tero

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#15 lore raw

v5 cover ARM: OMAP: PM usecounting changes

Quoted 8 lines · Tero Kristo
Quoted 7 lines · Rajendra Nayak

Hi Tero,

Quoted 3 lines · Tero Kristo

Hi,

Changes compared to previous version:

Quoted 8 lines
Quoted 2 lines

Did you get a chance to look at the issue I reported about autodeps?
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg72876.html

Not really, I didn't think that bug report was meant for me, I kind of thought it only happened with your set. But now looking at your email in detail, I guess you are saying there is a bug in this code (the one that touches iclk stuff), which causes the USB / DSS domains to follow MPU/CORE, is that right?

Yes, basically the autodeps remain set, even while the module is not in use at all, which causes them to come in and out of sleep along with MPU.

Quoted 55 lines

-Tero

Quoted 50 lines

regards,
Rajendra

Quoted 45 lines

- Fixed OMAP4 support (patches 7-10)
- Dropped debugging support from this set for now
- Rebased on top of 3.6-rc5 + func-pwrst + omap4-ret code (omap4 support easier to test with these)
- Patch #1:
* dropped clkdm_usecount_inc / clkdm_usecount_dec APIs
* clkdm_clk_enable / disable are used now instead
* some code ordering changed for the new setup to work properly
* changed BUG_ON calls to WARN_ON
- Patch #2:
* added spinlock for protecting voltdm callbacks
* pwrdm lock extended to protect pwrdm callbacks
- Patch #3:
* dropped generic API call for the cpu pwrdm idle / wakeup
* instead use pwrdm_clkdm_enable / disable calls directly from PM code
* omap4 support fixed to work properly with SMP, added omap4 specific CPU pwrdm idle / wakeup calls for this purpose
- Patch #4:
* no changes
* added 'Reviewed-by' tag for Rajendra
- Patch #5:
* no changes, just rebase
- Patch #6:
* no changes

Tested with OMAP3 beagle, omap4460 GP panda + omap4430 EMU blaze boards.

I will be posting new versions for the voltdm fixes + auto retention + panda board tps6236x support code later on today, which are based on top of this set.

Branch also available here:

git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.6-rc5-pwrdm-changes-v5

-Tero

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#16 lore raw

v5 cover ARM: OMAP: PM usecounting changes

Quoted 12 lines · Rajendra Nayak
Quoted 11 lines · Tero Kristo
Quoted 9 lines · Rajendra Nayak

Hi Tero,

Quoted 3 lines · Tero Kristo

Hi,

Changes compared to previous version:

Did you get a chance to look at the issue I reported about autodeps?
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg72876.html

Quoted 8 lines
Quoted 5 lines

Not really, I didn't think that bug report was meant for me, I kind of thought it only happened with your set. But now looking at your email in detail, I guess you are saying there is a bug in this code (the one that touches iclk stuff), which causes the USB / DSS domains to follow MPU/CORE, is that right?

Yes, basically the autodeps remain set, even while the module is not in use at all, which causes them to come in and out of sleep along with MPU.

Actually I think I accidentally fixed this problem with the latest rev, due to the fact that I am using generic clkdm_clk_enable / disable calls from iclk now.

I also just tested this (while fixing the complaint from Russell), and it looks like both USB and DSS pwrdms are remaining nicely idle on OMAP3.

-Tero

Quoted 57 lines
Quoted 56 lines

-Tero

Quoted 50 lines

regards,
Rajendra

Quoted 45 lines

- Fixed OMAP4 support (patches 7-10)
- Dropped debugging support from this set for now
- Rebased on top of 3.6-rc5 + func-pwrst + omap4-ret code (omap4 support easier to test with these)
- Patch #1:
* dropped clkdm_usecount_inc / clkdm_usecount_dec APIs
* clkdm_clk_enable / disable are used now instead
* some code ordering changed for the new setup to work properly
* changed BUG_ON calls to WARN_ON
- Patch #2:
* added spinlock for protecting voltdm callbacks
* pwrdm lock extended to protect pwrdm callbacks
- Patch #3:
* dropped generic API call for the cpu pwrdm idle / wakeup
* instead use pwrdm_clkdm_enable / disable calls directly from PM code
* omap4 support fixed to work properly with SMP, added omap4 specific CPU pwrdm idle / wakeup calls for this purpose
- Patch #4:
* no changes
* added 'Reviewed-by' tag for Rajendra
- Patch #5:
* no changes, just rebase
- Patch #6:
* no changes

Tested with OMAP3 beagle, omap4460 GP panda + omap4430 EMU blaze boards.

I will be posting new versions for the voltdm fixes + auto retention + panda board tps6236x support code later on today, which are based on top of this set.

Branch also available here:

git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.6-rc5-pwrdm-changes-v5

-Tero

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#17 lore raw

v5 cover ARM: OMAP: PM usecounting changes

Quoted 7 lines · Tero Kristo

Actually I think I accidentally fixed this problem with the latest rev, due to the fact that I am using generic clkdm_clk_enable / disable calls from iclk now.

I also just tested this (while fixing the complaint from Russell), and it looks like both USB and DSS pwrdms are remaining nicely idle on OMAP3.

oh, we are good in that case then. Thanks for the update.