linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv3 00/20] ARM: OMAP4: device off support
@ 2012-06-12 15:31 Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 01/20] ARM: OMAP4: PM: powerdomain: Add HWSAR flag to L3INIT Tero Kristo
                   ` (19 more replies)
  0 siblings, 20 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

V3 consists of following changes:

- ordering of patches changed (enable off-mode as last patch)
- rebased on top of 3.5-rc2
- rebased on top of Jean Pihet's functional power state code
- omap-secure driver has now its own CPU PM notifier:
  * moved dummy wakeup dispatcher call from omap-mpuss-lowpower.c
  * moved secure dispatcher calls from omap-wakeupgen.c
- device off mode is now enabled (in addition to previously just been
  traced) as a functional OFF state for core power domain
- added lots of kerneldoc comments
- dropped dpll_dump functionality from dpll44xx.c
- disabled device-off mode for early omap4430 GP chips (due to bugs
  impossible to support this mode on them)
- a number of other minor changes

Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.5-rc2-omap4-dev-off-v3

This tree is based on top of omap4 core retention tree.

Tested with omap4 panda es board (4460 GP) and omap4 blaze board (4430 EMU.)

-Tero

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCHv3 01/20] ARM: OMAP4: PM: powerdomain: Add HWSAR flag to L3INIT
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 02/20] ARM: OMAP4: powerdomain: update mpu / core off counters during device off Tero Kristo
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Santosh Shilimkar <santosh.shilimkar@ti.com>

L3INIT powerdomain has USB HOST and USB TLL modules which support
hardware save-and-restore (HW SAR) mechanism.
This patch updates the L3INIT power domain to mark them as capable
of doing H/w save and restore and provides functions to do them
explicitly.

Note: Eventually, these custom function implementation will be
abstracted and might be done in hwmod or in other layer.

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/powerdomain44xx.c       |   57 +++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c |    2 +-
 2 files changed, 58 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
index ab93f08..c63d580 100644
--- a/arch/arm/mach-omap2/powerdomain44xx.c
+++ b/arch/arm/mach-omap2/powerdomain44xx.c
@@ -23,6 +23,10 @@
 #include "prm44xx.h"
 #include "prminst44xx.h"
 #include "prm-regbits-44xx.h"
+#include "cm-regbits-44xx.h"
+#include "prcm44xx.h"
+#include "cm2_44xx.h"
+#include "cminst44xx.h"
 
 static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 {
@@ -265,6 +269,57 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 	return 0;
 }
 
+/**
+ * omap4_pwrdm_enable_hdwr_sar - enable hardware save / restore for pwrdm
+ * @pwrdm: struct powerdomain * to enable HW SAR for
+ *
+ * Enables hardware save / restore for a powerdomain. This is needed by
+ * some power domains to properly support off mode. Currently supports
+ * only L3INIT powerdomain on OMAP4. Called from powerdomain core code.
+ * Returns 0 always.
+ */
+static int omap4_pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
+{
+	/*
+	 * FIXME: This should be fixed right way by moving it into HWMOD
+	 * or clock framework since sar control is moved to module level
+	 */
+	omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK,
+		1 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION,
+		OMAP4430_CM2_L3INIT_INST,
+		OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET);
+	omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK,
+		1 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION,
+		OMAP4430_CM2_L3INIT_INST,
+		OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET);
+	return 0;
+}
+
+/**
+ * omap4_pwrdm_disable_hdwr_sar - disable hardware save / restore for pwrdm
+ * @pwrdm: struct powerdomain * to enable HW SAR for
+ *
+ * Disables hardware save / restore for a powerdomain. For OMAP4, supports
+ * currently only L3INIT powerdomain. Returns 0 always.
+ */
+static int omap4_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
+{
+	/*
+	 * FIXME: This should be fixed right way by moving it into HWMOD
+	 * or clock framework since sar control is moved to module level
+	 */
+	omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK,
+		0 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION,
+		OMAP4430_CM2_L3INIT_INST,
+		OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET);
+	omap4_cminst_rmw_inst_reg_bits(OMAP4430_SAR_MODE_MASK,
+		0 << OMAP4430_SAR_MODE_SHIFT, OMAP4430_CM2_PARTITION,
+		OMAP4430_CM2_L3INIT_INST,
+		OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET);
+
+	return 0;
+}
+
 struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
 	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
@@ -285,4 +340,6 @@ struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_set_mem_onst	= omap4_pwrdm_set_mem_onst,
 	.pwrdm_set_mem_retst	= omap4_pwrdm_set_mem_retst,
 	.pwrdm_wait_transition	= omap4_pwrdm_wait_transition,
+	.pwrdm_enable_hdwr_sar	= omap4_pwrdm_enable_hdwr_sar,
+	.pwrdm_disable_hdwr_sar	= omap4_pwrdm_disable_hdwr_sar,
 };
diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index 704664c..d8701ce 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -276,7 +276,7 @@ static struct powerdomain l3init_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* l3init_bank1 */
 	},
-	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE | PWRDM_HAS_HDWR_SAR,
 };
 
 /* l4per_44xx_pwrdm: Target peripherals power domain */
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 02/20] ARM: OMAP4: powerdomain: update mpu / core off counters during device off
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 01/20] ARM: OMAP4: PM: powerdomain: Add HWSAR flag to L3INIT Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 03/20] ARM: OMAP4: PM: add support for " Tero Kristo
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

Currently device off does not have any counters / timers of its own
and it is impossible to track the time spent in this state. In device
off, MPU / CORE powerdomains enter OSWR, so normally the OSWR
state times / counts are increased during device off.

This patch adds a new field to the powerdomain struct for context loss
register, which is checked during pwrdm_read_prev_func_pwrst to see if
a device off type context loss has happened. If this is the case,
the previous functional power state entered is shown as OFF and the
corresponding debug counters / timers are incremented. This patch
also adds a clear for the same register in the
omap4_pwrdm_clear_all_prev_pwrst function.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/powerdomain.c           |    4 +++
 arch/arm/mach-omap2/powerdomain.h           |    4 +++
 arch/arm/mach-omap2/powerdomain44xx.c       |   39 +++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c |    2 +
 4 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 2043f484..ac63f86 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -884,6 +884,10 @@ int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm)
 	int prev_pwrst = pwrdm_read_prev_pwrst(pwrdm);
 	int prev_logic = pwrdm_read_prev_logic_pwrst(pwrdm);
 
+	if (arch_pwrdm && arch_pwrdm->pwrdm_lost_context_rff &&
+	    arch_pwrdm->pwrdm_lost_context_rff(pwrdm))
+		return PWRDM_FUNC_PWRST_OFF;
+
 	return pwrdm_pwrst_to_func(pwrdm, prev_pwrst, prev_logic);
 }
 
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index a3dc859..0729d91 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -99,6 +99,7 @@ struct powerdomain;
  * @name: Powerdomain name
  * @voltdm: voltagedomain containing this powerdomain
  * @prcm_offs: the address offset from CM_BASE/PRM_BASE
+ * @context_offs: the address offset for the CONTEXT register
  * @prcm_partition: (OMAP4 only) the PRCM partition ID containing @prcm_offs
  * @pwrsts: Possible powerdomain power states
  * @pwrsts_logic_ret: Possible logic power states when pwrdm in RETENTION
@@ -123,6 +124,7 @@ struct powerdomain {
 		struct voltagedomain *ptr;
 	} voltdm;
 	const s16 prcm_offs;
+	const s16 context_offs;
 	const u8 pwrsts;
 	const u8 pwrsts_logic_ret;
 	const u8 flags;
@@ -171,6 +173,7 @@ struct powerdomain {
  * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd
  * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep
  * @pwrdm_wait_transition: Wait for a pd state transition to complete
+ * @pwrdm_lost_context_rff: Check if pd has lost RFF context (entered off)
  */
 struct pwrdm_ops {
 	int	(*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);
@@ -195,6 +198,7 @@ struct pwrdm_ops {
 	int	(*pwrdm_disable_hdwr_sar)(struct powerdomain *pwrdm);
 	int	(*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
 	int	(*pwrdm_wait_transition)(struct powerdomain *pwrdm);
+	bool	(*pwrdm_lost_context_rff)(struct powerdomain *pwrdm);
 };
 
 int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
index c63d580..562f78a 100644
--- a/arch/arm/mach-omap2/powerdomain44xx.c
+++ b/arch/arm/mach-omap2/powerdomain44xx.c
@@ -88,6 +88,14 @@ static int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
 					OMAP4430_LASTPOWERSTATEENTERED_MASK,
 					pwrdm->prcm_partition,
 					pwrdm->prcm_offs, OMAP4_PM_PWSTST);
+
+	if (pwrdm->context_offs)
+		omap4_prminst_write_inst_reg(OMAP4430_LOSTCONTEXT_DFF_MASK |
+					     OMAP4430_LOSTCONTEXT_RFF_MASK,
+					     pwrdm->prcm_partition,
+					     pwrdm->prcm_offs,
+					     pwrdm->context_offs);
+
 	return 0;
 }
 
@@ -320,6 +328,36 @@ static int omap4_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 	return 0;
 }
 
+/**
+ * omap4_pwrdm_lost_context_rff - check if a pwrdm has lost it rff context
+ * @pwrdm: struct powerdomain * to check
+ *
+ * Checks if the powerdomain has lost its RFF context or not. Basically
+ * this means if the device has entered off or not. Returns true if the
+ * context has been lost, false otherwise.
+ */
+bool omap4_pwrdm_lost_context_rff(struct powerdomain *pwrdm)
+{
+	u32 val;
+	s16 inst, offset;
+
+	if (!pwrdm)
+		return false;
+
+	inst = pwrdm->prcm_offs;
+	offset = pwrdm->context_offs;
+
+	if (!offset)
+		return false;
+
+	val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, inst, offset);
+
+	if (val & OMAP4430_LOSTCONTEXT_RFF_MASK)
+		return true;
+
+	return false;
+}
+
 struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
 	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
@@ -342,4 +380,5 @@ struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_wait_transition	= omap4_pwrdm_wait_transition,
 	.pwrdm_enable_hdwr_sar	= omap4_pwrdm_enable_hdwr_sar,
 	.pwrdm_disable_hdwr_sar	= omap4_pwrdm_disable_hdwr_sar,
+	.pwrdm_lost_context_rff = omap4_pwrdm_lost_context_rff,
 };
diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index d8701ce..c4de02f 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -36,6 +36,7 @@ static struct powerdomain core_44xx_pwrdm = {
 	.voltdm		  = { .name = "core" },
 	.prcm_offs	  = OMAP4430_PRM_CORE_INST,
 	.prcm_partition	  = OMAP4430_PRM_PARTITION,
+	.context_offs	  = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET,
 	.pwrsts		  = PWRSTS_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 5,
@@ -205,6 +206,7 @@ static struct powerdomain mpu_44xx_pwrdm = {
 	.voltdm		  = { .name = "mpu" },
 	.prcm_offs	  = OMAP4430_PRM_MPU_INST,
 	.prcm_partition	  = OMAP4430_PRM_PARTITION,
+	.context_offs	  = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET,
 	.pwrsts		  = PWRSTS_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 3,
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 03/20] ARM: OMAP4: PM: add support for device off
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 01/20] ARM: OMAP4: PM: powerdomain: Add HWSAR flag to L3INIT Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 02/20] ARM: OMAP4: powerdomain: update mpu / core off counters during device off Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-13 15:21   ` Jean Pihet
  2012-06-12 15:31 ` [PATCHv3 04/20] ARM: OMAP4: PM: update ROM return address for OSWR and OFF Tero Kristo
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

On OMAP4+, device wide off-mode has its own enable mechanism in addition
to powerdomain target states. This patch adds support for this on top
of functional power states by overloading the OFF state for core pwrdm.
On pwrdm level, the deepest power state supported by core pwrdm is OSWR.
When user (e.g. suspend) programs core pwrdm target as OFF, the functional
power state for the domain will be OSWR with the additional device off
enabled. Previous power state information will reflect this also.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/powerdomain.c           |   17 +++++++++
 arch/arm/mach-omap2/powerdomain.h           |   13 +++++++-
 arch/arm/mach-omap2/powerdomain44xx.c       |   48 +++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c |    3 +-
 4 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index ac63f86..78a9308 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -677,6 +677,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
 	int sleep_switch = -1, ret = 0, hwsup = 0;
 	int new_func_pwrst, next_func_pwrst, pwrst, logic;
 	u8 curr_pwrst;
+	bool extra_off_enable = false;
+	bool has_extra_off = false;
 
 	if (!pwrdm || IS_ERR(pwrdm)) {
 		pr_debug("%s: invalid params: pwrdm=%p\n", __func__, pwrdm);
@@ -687,6 +689,13 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
 
 	mutex_lock(&pwrdm->lock);
 
+	/* Check if powerdomain has extra off mode handling */
+	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE) {
+		has_extra_off = true;
+		if (func_pwrst == PWRDM_FUNC_PWRST_OFF)
+			extra_off_enable = true;
+	}
+
 	new_func_pwrst = pwrdm_get_achievable_func_pwrst(pwrdm, func_pwrst);
 	pwrst = pwrdm_func_to_pwrst(pwrdm, new_func_pwrst);
 	logic = pwrdm_func_to_logic_pwrst(pwrdm, new_func_pwrst);
@@ -741,6 +750,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
 		break;
 	}
 
+	if (has_extra_off && arch_pwrdm->pwrdm_enable_off)
+		arch_pwrdm->pwrdm_enable_off(pwrdm, extra_off_enable);
+
 out:
 	mutex_unlock(&pwrdm->lock);
 	return ret;
@@ -810,6 +822,11 @@ int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)
 	int next_pwrst = pwrdm_read_next_pwrst(pwrdm);
 	int next_logic = pwrdm_read_logic_retst(pwrdm);
 
+	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE &&
+	    arch_pwrdm->pwrdm_read_next_off &&
+	    arch_pwrdm->pwrdm_read_next_off(pwrdm))
+		return PWRDM_FUNC_PWRST_OFF;
+
 	return pwrdm_pwrst_to_func(pwrdm, next_pwrst, next_logic);
 }
 
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 0729d91..cc30b94 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -75,6 +75,13 @@
 						  * state without waking up the
 						  * powerdomain
 						  */
+/*
+ * OMAP4+ has device off feature, which must be enabled separately in
+ * addition to power domain next state setup. This feature is overloaded
+ * as EXTRA_OFF_ENABLE for core_pwrdm, and is implemented on top of
+ * functional power state
+ */
+#define PWRDM_HAS_EXTRA_OFF_ENABLE	(1 << 3)
 
 /*
  * Number of memory banks that are power-controllable.	On OMAP4430, the
@@ -173,7 +180,9 @@ struct powerdomain {
  * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd
  * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep
  * @pwrdm_wait_transition: Wait for a pd state transition to complete
- * @pwrdm_lost_context_rff: Check if pd has lost RFF context (entered off)
+ * @pwrdm_lost_context_rff: Check if pd has lost RFF context (omap4+ device off)
+ * @pwrdm_enable_off: Extra off mode enable for pd (omap4+ device off)
+ * @pwrdm_read_next_off: Check if pd next state is off (omap4+ device off)
  */
 struct pwrdm_ops {
 	int	(*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);
@@ -199,6 +208,8 @@ struct pwrdm_ops {
 	int	(*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
 	int	(*pwrdm_wait_transition)(struct powerdomain *pwrdm);
 	bool	(*pwrdm_lost_context_rff)(struct powerdomain *pwrdm);
+	void	(*pwrdm_enable_off)(struct powerdomain *pwrdm, bool enable);
+	bool	(*pwrdm_read_next_off)(struct powerdomain *pwrdm);
 };
 
 int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
index 562f78a..b2bdc0f 100644
--- a/arch/arm/mach-omap2/powerdomain44xx.c
+++ b/arch/arm/mach-omap2/powerdomain44xx.c
@@ -358,6 +358,52 @@ bool omap4_pwrdm_lost_context_rff(struct powerdomain *pwrdm)
 	return false;
 }
 
+/**
+ * omap4_device_set_next_state_off - setup device off state
+ * @pwrdm: struct powerdomain * to target powerdomain
+ * @enable: true if off-mode should be enabled
+ *
+ * When Device OFF is enabled, Device is allowed to perform
+ * transition to off mode as soon as all power domains in MPU, IVA
+ * and CORE voltage are in OFF or OSWR state (open switch retention)
+ */
+void omap4_device_set_next_state_off(struct powerdomain *pwrdm, bool enable)
+{
+	u8 val = enable ? 0x1 : 0x0;
+
+	if (!(pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE))
+		return;
+
+	omap4_prminst_write_inst_reg(val << OMAP4430_DEVICE_OFF_ENABLE_SHIFT,
+				     OMAP4430_PRM_PARTITION,
+				     OMAP4430_PRM_DEVICE_INST,
+				     OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET);
+}
+
+
+/**
+ * omap4_device_read_next_state_off - read device off state
+ * @pwrdm: struct powerdomain * to target powerdomain
+ *
+ * Checks if device off is enabled or not.
+ * Returns true if enabled, false otherwise.
+ */
+bool omap4_device_read_next_state_off(struct powerdomain *pwrdm)
+{
+	u32 val;
+
+	if (!(pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE))
+		return false;
+
+	val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
+					  OMAP4430_PRM_DEVICE_INST,
+					  OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET);
+
+	val &= OMAP4430_DEVICE_OFF_ENABLE_MASK;
+
+	return val ? true : false;
+}
+
 struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
 	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
@@ -381,4 +427,6 @@ struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_enable_hdwr_sar	= omap4_pwrdm_enable_hdwr_sar,
 	.pwrdm_disable_hdwr_sar	= omap4_pwrdm_disable_hdwr_sar,
 	.pwrdm_lost_context_rff = omap4_pwrdm_lost_context_rff,
+	.pwrdm_enable_off	= omap4_device_set_next_state_off,
+	.pwrdm_read_next_off	= omap4_device_read_next_state_off,
 };
diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index c4de02f..13db876 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -54,7 +54,8 @@ static struct powerdomain core_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* ducati_l2ram */
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
-	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE |
+			    PWRDM_HAS_EXTRA_OFF_ENABLE,
 };
 
 /* gfx_44xx_pwrdm: 3D accelerator power domain */
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 04/20] ARM: OMAP4: PM: update ROM return address for OSWR and OFF
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (2 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 03/20] ARM: OMAP4: PM: add support for " Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 05/20] OMAP4: PM: clockdomain: workaround for l4_secure_clkdm HWSUP Tero Kristo
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Carlos Leija <cileija@ti.com>

At wakeup from OFF/OSWR CPU1 will call secure HAL service through a local
secure dispatcher with MMU off (from omap-headsmp.S), thus ROM will save
a PA return address. Later in the wakeup, when SMC driver calls an RPC through
omap4_secure_dispatcher (MMU is on now), ROM code won't log the new return
address as RPCs are handled different. Thus ROM will attempt to return to
a PA address when the MMU is on and the system will hang.

We need to do this for OSWR state and OFF state of mpu power domain,
not just for device off(mpu pd OFF).

Original workaround was written by:
  Carlos Leija <cileija@ti.com>
  Praneeth Bajjuri <praneeth@ti.com>
  Bryan Buckley <bryan.buckley@ti.com>

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/include/mach/omap-secure.h |    1 +
 arch/arm/mach-omap2/omap-secure.c              |   36 ++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/include/mach/omap-secure.h b/arch/arm/mach-omap2/include/mach/omap-secure.h
index c90a435..d9bde61 100644
--- a/arch/arm/mach-omap2/include/mach/omap-secure.h
+++ b/arch/arm/mach-omap2/include/mach/omap-secure.h
@@ -43,6 +43,7 @@
 #define OMAP4_MON_L2X0_PREFETCH_INDEX	0x113
 
 /* Secure PPA(Primary Protected Application) APIs */
+#define OMAP4_PPA_SERVICE_0		0x21
 #define OMAP4_PPA_L2_POR_INDEX		0x23
 #define OMAP4_PPA_CPU_ACTRL_SMP_INDEX	0x25
 
diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index d9ae4a5..36ec5a5 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/memblock.h>
+#include <linux/cpu_pm.h>
 
 #include <asm/cacheflush.h>
 #include <asm/memblock.h>
@@ -21,6 +22,8 @@
 #include <plat/omap-secure.h>
 #include <mach/omap-secure.h>
 
+#include "common.h"
+
 static phys_addr_t omap_secure_memblock_base;
 
 /**
@@ -71,3 +74,36 @@ phys_addr_t omap_secure_ram_mempool_base(void)
 {
 	return omap_secure_memblock_base;
 }
+
+#ifdef CONFIG_CPU_PM
+static int secure_notifier(struct notifier_block *self, unsigned long cmd,
+			   void *v)
+{
+	switch (cmd) {
+	case CPU_CLUSTER_PM_EXIT:
+		/*
+		 * Dummy dispatcher call after OSWR and OFF
+		 * Restore the right return Kernel address (with MMU on) for
+		 * subsequent calls to secure ROM. Otherwise the return address
+		 * will be to a PA return address and the system will hang.
+		 */
+		omap_secure_dispatcher(OMAP4_PPA_SERVICE_0,
+				       FLAG_START_CRITICAL,
+				       0, 0, 0, 0, 0);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block secure_notifier_block = {
+	.notifier_call = secure_notifier,
+};
+
+static int __init secure_pm_init(void)
+{
+	if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+		cpu_pm_register_notifier(&secure_notifier_block);
+	return 0;
+}
+early_initcall(secure_pm_init);
+#endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 05/20] OMAP4: PM: clockdomain: workaround for l4_secure_clkdm HWSUP
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (3 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 04/20] ARM: OMAP4: PM: update ROM return address for OSWR and OFF Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 06/20] ARM: OMAP4: secure: move GIC / wakeupgen save restore to secure CPU PM notifier Tero Kristo
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Santosh Shilimkar <santosh.shilimkar@ti.com>

On HS/EMU devices the modules from l4_secure_clkdm are used. Few modules from
L4_SEC clockdomain are not accessible without putting l4_secure_clkdm in
force software wakeup.

Follow the recommended sequence across secure API calls.

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-secure.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index 36ec5a5..eeb8114 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -24,7 +24,10 @@
 
 #include "common.h"
 
+#include "clockdomain.h"
+
 static phys_addr_t omap_secure_memblock_base;
+static struct clockdomain *l4_secure_clkdm;
 
 /**
  * omap_sec_dispatcher: Routine to dispatch low power secure
@@ -48,6 +51,11 @@ u32 omap_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2,
 	param[3] = arg3;
 	param[4] = arg4;
 
+	if (!l4_secure_clkdm)
+		l4_secure_clkdm = clkdm_lookup("l4_secure_clkdm");
+
+	clkdm_wakeup(l4_secure_clkdm);
+
 	/*
 	 * Secure API needs physical address
 	 * pointer for the parameters
@@ -56,6 +64,8 @@ u32 omap_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2,
 	outer_clean_range(__pa(param), __pa(param + 5));
 	ret = omap_smc2(idx, flag, __pa(param));
 
+	clkdm_allow_idle(l4_secure_clkdm);
+
 	return ret;
 }
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 06/20] ARM: OMAP4: secure: move GIC / wakeupgen save restore to secure CPU PM notifier
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (4 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 05/20] OMAP4: PM: clockdomain: workaround for l4_secure_clkdm HWSUP Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 07/20] ARM: OMAP4: secure: add support for device off Tero Kristo
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

As secure driver now has CPU PM notifier, move the security involved
tweaks from wakeupgen to here. This allows us to drop some runtime
omap chip type checks away also, as wakeupgen CPU PM notifier is no
longer needed at all on secure devices.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-secure.c    |   14 ++++++++++++++
 arch/arm/mach-omap2/omap-wakeupgen.c |   31 +++++++++----------------------
 2 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index eeb8114..44905a5 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -86,6 +86,17 @@ phys_addr_t omap_secure_ram_mempool_base(void)
 }
 
 #ifdef CONFIG_CPU_PM
+static void save_secure_gic(void)
+{
+	u32 ret;
+
+	ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX,
+				     FLAG_START_CRITICAL,
+				     0, 0, 0, 0, 0);
+	if (ret != API_HAL_RET_VALUE_OK)
+		pr_err("GIC and Wakeupgen secure context save failed\n");
+}
+
 static int secure_notifier(struct notifier_block *self, unsigned long cmd,
 			   void *v)
 {
@@ -101,6 +112,9 @@ static int secure_notifier(struct notifier_block *self, unsigned long cmd,
 				       FLAG_START_CRITICAL,
 				       0, 0, 0, 0, 0);
 		break;
+	case CPU_CLUSTER_PM_ENTER:
+		save_secure_gic();
+		break;
 	}
 	return NOTIFY_OK;
 }
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index d811c77..1cffb3a 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -28,7 +28,6 @@
 #include <asm/hardware/gic.h>
 
 #include <mach/omap-wakeupgen.h>
-#include <mach/omap-secure.h>
 
 #include "omap4-sar-layout.h"
 #include "common.h"
@@ -266,20 +265,6 @@ static void irq_sar_clear(void)
 	val &= ~SAR_BACKUP_STATUS_WAKEUPGEN;
 	__raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET);
 }
-
-/*
- * Save GIC and Wakeupgen interrupt context using secure API
- * for HS/EMU devices.
- */
-static void irq_save_secure_context(void)
-{
-	u32 ret;
-	ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX,
-				FLAG_START_CRITICAL,
-				0, 0, 0, 0, 0);
-	if (ret != API_HAL_RET_VALUE_OK)
-		pr_err("GIC and Wakeupgen context save failed\n");
-}
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -317,14 +302,10 @@ static int irq_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
 {
 	switch (cmd) {
 	case CPU_CLUSTER_PM_ENTER:
-		if (omap_type() == OMAP2_DEVICE_TYPE_GP)
-			irq_save_context();
-		else
-			irq_save_secure_context();
+		irq_save_context();
 		break;
 	case CPU_CLUSTER_PM_EXIT:
-		if (omap_type() == OMAP2_DEVICE_TYPE_GP)
-			irq_sar_clear();
+		irq_sar_clear();
 		break;
 	}
 	return NOTIFY_OK;
@@ -336,7 +317,13 @@ static struct notifier_block irq_notifier_block = {
 
 static void __init irq_pm_init(void)
 {
-	cpu_pm_register_notifier(&irq_notifier_block);
+	/*
+	 * Register CPU_PM notifier only on GP devices, as saving
+	 * GIC context will involve secure API calls on secure
+	 * devices. Secure driver will handle these.
+	 */
+	if (omap_type() == OMAP2_DEVICE_TYPE_GP)
+		cpu_pm_register_notifier(&irq_notifier_block);
 }
 #else
 static void __init irq_pm_init(void)
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 07/20] ARM: OMAP4: secure: add support for device off
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (5 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 06/20] ARM: OMAP4: secure: move GIC / wakeupgen save restore to secure CPU PM notifier Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 08/20] ARM: OMAP4: PM: add MPUSS power domain device off support Tero Kristo
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

If omap4 chip enters device off, complete secure context must be saved.
This requires a separate secure HAL call. As device off mode is overloaded
on top of functional core_pwrdm state, the code checks if core_pwrdm is
entering off mode, and does the complete context save in that case.
Otherwise the GIC save context is enough.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-secure.c |   48 +++++++++++++++++++++++++++++++++++-
 1 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index 44905a5..340b11a 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -21,6 +21,7 @@
 
 #include <plat/omap-secure.h>
 #include <mach/omap-secure.h>
+#include <plat/omap_hwmod.h>
 
 #include "common.h"
 
@@ -28,6 +29,8 @@
 
 static phys_addr_t omap_secure_memblock_base;
 static struct clockdomain *l4_secure_clkdm;
+static struct powerdomain *core_pd;
+static struct omap_hwmod *l3_main_3_oh;
 
 /**
  * omap_sec_dispatcher: Routine to dispatch low power secure
@@ -97,6 +100,29 @@ static void save_secure_gic(void)
 		pr_err("GIC and Wakeupgen secure context save failed\n");
 }
 
+static void save_secure_all(void)
+{
+	u32 ret;
+
+	/*
+	 * l3_main_3 must be enabled before calling SAVEALL API,
+	 * as it is accessing firewall registers which require this
+	 * clock to be enabled. Otherwise secure ROM code will crash.
+	 */
+	omap_hwmod_enable(l3_main_3_oh);
+
+	ret = omap_secure_dispatcher(OMAP4_HAL_SAVEALL_INDEX,
+				     FLAG_START_CRITICAL,
+				     1, omap_secure_ram_mempool_base(),
+				     0, 0, 0);
+
+	/* Disable after save, not needed anymore */
+	omap_hwmod_idle(l3_main_3_oh);
+
+	if (ret != API_HAL_RET_VALUE_OK)
+		pr_err("Secure all context save failed\n");
+}
+
 static int secure_notifier(struct notifier_block *self, unsigned long cmd,
 			   void *v)
 {
@@ -113,7 +139,16 @@ static int secure_notifier(struct notifier_block *self, unsigned long cmd,
 				       0, 0, 0, 0, 0);
 		break;
 	case CPU_CLUSTER_PM_ENTER:
-		save_secure_gic();
+		/*
+		 * If device is entering off-mode (core_pd next functional
+		 * pwrst = OFF), we must save complete secure mode context.
+		 * Otherwise just saving GIC / wakeupgen context is enough.
+		 */
+		if (pwrdm_read_next_func_pwrst(core_pd) ==
+		    PWRDM_FUNC_PWRST_OFF)
+			save_secure_all();
+		else
+			save_secure_gic();
 		break;
 	}
 	return NOTIFY_OK;
@@ -125,8 +160,17 @@ static struct notifier_block secure_notifier_block = {
 
 static int __init secure_pm_init(void)
 {
-	if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+	if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
 		cpu_pm_register_notifier(&secure_notifier_block);
+
+		l3_main_3_oh = omap_hwmod_lookup("l3_main_3");
+		if (!l3_main_3_oh)
+			pr_err("%s: failed to get l3_main_3_oh\n", __func__);
+
+		core_pd = pwrdm_lookup("core_pwrdm");
+		if (!core_pd)
+			pr_err("%s: failed to get core_pwrdm\n", __func__);
+	}
 	return 0;
 }
 early_initcall(secure_pm_init);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 08/20] ARM: OMAP4: PM: add MPUSS power domain device off support
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (6 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 07/20] ARM: OMAP4: secure: add support for device off Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 09/20] ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode Tero Kristo
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds device off support for MPUSS power domain. Device off
support is overloaded on top of core pwrdm functional OFF powerstate,
so the code must check the next core powerstate and set the save_state
status accordingly.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 0e5f81b..0155242 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -72,7 +72,7 @@ struct omap4_cpu_pm_info {
 };
 
 static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
-static struct powerdomain *mpuss_pd;
+static struct powerdomain *mpuss_pd, *core_pd;
 static void __iomem *sar_base;
 
 /*
@@ -265,7 +265,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 * In MPUSS OSWR or device OFF, interrupt controller context is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	if (pwrdm_read_next_func_pwrst(mpuss_pd) == PWRDM_FUNC_PWRST_OSWR)
+	if (pwrdm_read_next_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF)
+		save_state = 3;
+	else if (pwrdm_read_next_func_pwrst(mpuss_pd) == PWRDM_FUNC_PWRST_OSWR)
 		save_state = 2;
 
 	cpu_clear_prev_logic_pwrst(cpu);
@@ -386,6 +388,11 @@ int __init omap4_mpuss_init(void)
 		pr_err("Failed to lookup MPUSS power domain\n");
 		return -ENODEV;
 	}
+	core_pd = pwrdm_lookup("core_pwrdm");
+	if (!core_pd) {
+		pr_err("Failed to lookup CORE power domain\n");
+		return -ENODEV;
+	}
 	pwrdm_clear_all_prev_pwrst(mpuss_pd);
 	mpuss_clear_prev_logic_pwrst();
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 09/20] ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (7 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 08/20] ARM: OMAP4: PM: add MPUSS power domain device off support Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 10/20] ARM: OMAP4: PM: save/restore all CM1/2 " Tero Kristo
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Rajendra Nayak <rnayak@ti.com>

SAR/ROM code restores only CORE DPLL to its original state
post wakeup from OFF mode.
The rest of the DPLL's in OMAP4 platform (MPU/IVA/ABE/USB/PER)
are saved and restored here during an OFF transition.

[nm at ti.com: minor cleanups]
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/cm44xx.h              |    5 +
 arch/arm/mach-omap2/dpll44xx.c            |  225 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   11 ++-
 3 files changed, 239 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h
index 3380bee..5fba0fa 100644
--- a/arch/arm/mach-omap2/cm44xx.h
+++ b/arch/arm/mach-omap2/cm44xx.h
@@ -23,4 +23,9 @@
 #define OMAP4_CM_CLKSTCTRL				0x0000
 #define OMAP4_CM_STATICDEP				0x0004
 
+#ifndef __ASSEMBLER__
+extern void omap4_dpll_prepare_off(void);
+extern void omap4_dpll_resume_off(void);
+#endif
+
 #endif
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index 9c6a296..f903057 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <plat/cpu.h>
 #include <plat/clock.h>
@@ -21,6 +22,96 @@
 #include "clock.h"
 #include "clock44xx.h"
 #include "cm-regbits-44xx.h"
+#include "cm1_44xx.h"
+#include "cm2_44xx.h"
+#include "prcm44xx.h"
+#include "cminst44xx.h"
+#include "cm44xx.h"
+
+#define MAX_DPLL_WAIT_TRIES	1000000
+
+struct dpll_reg {
+	u16 offset;
+	u32 val;
+};
+
+struct omap4_dpll_regs {
+	char *name;
+	u32 mod_partition;
+	u32 mod_inst;
+	struct dpll_reg clkmode;
+	struct dpll_reg autoidle;
+	struct dpll_reg idlest;
+	struct dpll_reg clksel;
+	struct dpll_reg div_m2;
+	struct dpll_reg div_m3;
+	struct dpll_reg div_m4;
+	struct dpll_reg div_m5;
+	struct dpll_reg div_m6;
+	struct dpll_reg div_m7;
+	struct dpll_reg clkdcoldo;
+};
+
+static struct omap4_dpll_regs dpll_regs[] = {
+	/* MPU DPLL */
+	{ .name		= "mpu",
+	  .mod_partition = OMAP4430_CM1_PARTITION,
+	  .mod_inst	= OMAP4430_CM1_CKGEN_INST,
+	  .clkmode	= {.offset = OMAP4_CM_CLKMODE_DPLL_MPU_OFFSET},
+	  .autoidle	= {.offset = OMAP4_CM_AUTOIDLE_DPLL_MPU_OFFSET},
+	  .idlest	= {.offset = OMAP4_CM_IDLEST_DPLL_MPU_OFFSET},
+	  .clksel	= {.offset = OMAP4_CM_CLKSEL_DPLL_MPU_OFFSET},
+	  .div_m2	= {.offset = OMAP4_CM_DIV_M2_DPLL_MPU_OFFSET},
+	},
+	/* IVA DPLL */
+	{ .name		= "iva",
+	  .mod_partition = OMAP4430_CM1_PARTITION,
+	  .mod_inst	= OMAP4430_CM1_CKGEN_INST,
+	  .clkmode	= {.offset = OMAP4_CM_CLKMODE_DPLL_IVA_OFFSET},
+	  .autoidle	= {.offset = OMAP4_CM_AUTOIDLE_DPLL_IVA_OFFSET},
+	  .idlest	= {.offset = OMAP4_CM_IDLEST_DPLL_IVA_OFFSET},
+	  .clksel	= {.offset = OMAP4_CM_CLKSEL_DPLL_IVA_OFFSET},
+	  .div_m4	= {.offset = OMAP4_CM_DIV_M4_DPLL_IVA_OFFSET},
+	  .div_m5	= {.offset = OMAP4_CM_DIV_M5_DPLL_IVA_OFFSET},
+	},
+	/* ABE DPLL */
+	{ .name		= "abe",
+	  .mod_partition = OMAP4430_CM1_PARTITION,
+	  .mod_inst	= OMAP4430_CM1_CKGEN_INST,
+	  .clkmode	= {.offset = OMAP4_CM_CLKMODE_DPLL_ABE_OFFSET},
+	  .autoidle	= {.offset = OMAP4_CM_AUTOIDLE_DPLL_ABE_OFFSET},
+	  .idlest	= {.offset = OMAP4_CM_IDLEST_DPLL_ABE_OFFSET},
+	  .clksel	= {.offset = OMAP4_CM_CLKSEL_DPLL_ABE_OFFSET},
+	  .div_m2	= {.offset = OMAP4_CM_DIV_M2_DPLL_ABE_OFFSET},
+	  .div_m3	= {.offset = OMAP4_CM_DIV_M3_DPLL_ABE_OFFSET},
+	},
+	/* USB DPLL */
+	{ .name		= "usb",
+	  .mod_partition = OMAP4430_CM2_PARTITION,
+	  .mod_inst	= OMAP4430_CM2_CKGEN_INST,
+	  .clkmode	= {.offset = OMAP4_CM_CLKMODE_DPLL_USB_OFFSET},
+	  .autoidle	= {.offset = OMAP4_CM_AUTOIDLE_DPLL_USB_OFFSET},
+	  .idlest	= {.offset = OMAP4_CM_IDLEST_DPLL_USB_OFFSET},
+	  .clksel	= {.offset = OMAP4_CM_CLKSEL_DPLL_USB_OFFSET},
+	  .div_m2	= {.offset = OMAP4_CM_DIV_M2_DPLL_USB_OFFSET},
+	  .clkdcoldo	= {.offset = OMAP4_CM_CLKDCOLDO_DPLL_USB_OFFSET},
+	 },
+	/* PER DPLL */
+	{ .name		= "per",
+	  .mod_partition = OMAP4430_CM2_PARTITION,
+	  .mod_inst	= OMAP4430_CM2_CKGEN_INST,
+	  .clkmode	= {.offset = OMAP4_CM_CLKMODE_DPLL_PER_OFFSET},
+	  .autoidle	= {.offset = OMAP4_CM_AUTOIDLE_DPLL_PER_OFFSET},
+	  .idlest	= {.offset = OMAP4_CM_IDLEST_DPLL_PER_OFFSET},
+	  .clksel	= {.offset = OMAP4_CM_CLKSEL_DPLL_PER_OFFSET},
+	  .div_m2	= {.offset = OMAP4_CM_DIV_M2_DPLL_PER_OFFSET},
+	  .div_m3	= {.offset = OMAP4_CM_DIV_M3_DPLL_PER_OFFSET},
+	  .div_m4	= {.offset = OMAP4_CM_DIV_M4_DPLL_PER_OFFSET},
+	  .div_m5	= {.offset = OMAP4_CM_DIV_M5_DPLL_PER_OFFSET},
+	  .div_m6	= {.offset = OMAP4_CM_DIV_M6_DPLL_PER_OFFSET},
+	  .div_m7	= {.offset = OMAP4_CM_DIV_M7_DPLL_PER_OFFSET},
+	},
+};
 
 /* Supported only on OMAP4 */
 int omap4_dpllmx_gatectrl_read(struct clk *clk)
@@ -151,3 +242,137 @@ long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate)
 
 	return clk->dpll_data->last_rounded_rate;
 }
+
+/**
+ * omap4_dpll_read_reg - reads DPLL register value
+ * @dpll_reg: DPLL register to read
+ *
+ * Reads the value of a single DPLL register.
+ */
+static inline u32 omap4_dpll_read_reg(struct omap4_dpll_regs *dpll_reg,
+				      struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		return omap4_cminst_read_inst_reg(dpll_reg->mod_partition,
+						  dpll_reg->mod_inst,
+						  tuple->offset);
+	return 0;
+}
+
+/**
+ * omap4_dpll_store_reg - stores DPLL register value to memory location
+ * @dpll_reg: DPLL register to save
+ * @tuple: save address
+ *
+ * Saves a single DPLL register content to memory location defined by
+ * @tuple before entering device off mode.
+ */
+static inline void omap4_dpll_store_reg(struct omap4_dpll_regs *dpll_reg,
+					struct dpll_reg *tuple)
+{
+	tuple->val = omap4_dpll_read_reg(dpll_reg, tuple);
+}
+
+/**
+ * omap4_dpll_prepare_off - stores DPLL settings before off mode
+ *
+ * Saves all DPLL register settings. This must be called before
+ * entering device off.
+ */
+void omap4_dpll_prepare_off(void)
+{
+	u32 i;
+	struct omap4_dpll_regs *dpll_reg = dpll_regs;
+
+	for (i = 0; i < ARRAY_SIZE(dpll_regs); i++, dpll_reg++) {
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->clkmode);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->autoidle);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->clksel);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m2);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m3);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m4);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m5);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m6);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->div_m7);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->clkdcoldo);
+		omap4_dpll_store_reg(dpll_reg, &dpll_reg->idlest);
+	}
+}
+
+/**
+ * omap4_wait_dpll_lock - wait for a DPLL lock
+ * @dpll_reg: DPLL to wait for
+ *
+ * Waits for a DPLL lock after restore.
+ */
+static void omap4_wait_dpll_lock(struct omap4_dpll_regs *dpll_reg)
+{
+	int j = 0;
+	u32 status;
+
+	/* Return if we dont need to lock. */
+	if ((dpll_reg->clkmode.val & OMAP4430_DPLL_EN_MASK) !=
+	     DPLL_LOCKED << OMAP4430_DPLL_EN_SHIFT)
+		return;
+
+	while (1) {
+		status = (omap4_dpll_read_reg(dpll_reg, &dpll_reg->idlest)
+			  & OMAP4430_ST_DPLL_CLK_MASK)
+			 >> OMAP4430_ST_DPLL_CLK_SHIFT;
+		if (status == 0x1)
+			break;
+		if (j == MAX_DPLL_WAIT_TRIES) {
+			/* If we are unable to lock, warn and move on.. */
+			pr_err("Failed to lock dpll %s\n", dpll_reg->name);
+			break;
+		}
+		j++;
+		udelay(1);
+	}
+}
+
+/**
+ * omap4_dpll_restore_reg - restores a single register for a DPLL
+ * @dpll_reg: DPLL to restore
+ * @tuple: register value to restore
+ *
+ * Restores a single register for a DPLL.
+ */
+static inline void omap4_dpll_restore_reg(struct omap4_dpll_regs *dpll_reg,
+					  struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		omap4_cminst_write_inst_reg(tuple->val, dpll_reg->mod_partition,
+					    dpll_reg->mod_inst, tuple->offset);
+}
+
+/**
+ * omap4_dpll_resume_off - restore DPLL settings after device off
+ *
+ * Restores all DPLL settings. Must be called after wakeup from device
+ * off.
+ */
+void omap4_dpll_resume_off(void)
+{
+	u32 i;
+	struct omap4_dpll_regs *dpll_reg = dpll_regs;
+
+	for (i = 0; i < ARRAY_SIZE(dpll_regs); i++, dpll_reg++) {
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->clksel);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m2);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m3);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m4);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m5);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m6);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->div_m7);
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->clkdcoldo);
+
+		/* Restore clkmode after the above registers are restored */
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->clkmode);
+
+		omap4_wait_dpll_lock(dpll_reg);
+
+		/* Restore autoidle settings after the dpll is locked */
+		omap4_dpll_restore_reg(dpll_reg, &dpll_reg->autoidle);
+	}
+}
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 0155242..805ee38 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -60,6 +60,7 @@
 #include "prcm44xx.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
+#include "cm44xx.h"
 
 #ifdef CONFIG_SMP
 
@@ -265,10 +266,13 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 * In MPUSS OSWR or device OFF, interrupt controller context is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	if (pwrdm_read_next_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF)
+	if (pwrdm_read_next_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF) {
+		omap4_dpll_prepare_off();
 		save_state = 3;
-	else if (pwrdm_read_next_func_pwrst(mpuss_pd) == PWRDM_FUNC_PWRST_OSWR)
+	} else if (pwrdm_read_next_func_pwrst(mpuss_pd) ==
+		   PWRDM_FUNC_PWRST_OSWR) {
 		save_state = 2;
+	}
 
 	cpu_clear_prev_logic_pwrst(cpu);
 	set_cpu_next_pwrst(cpu, power_state);
@@ -291,6 +295,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_FUNC_PWRST_ON);
 
+	if (pwrdm_read_prev_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF)
+		omap4_dpll_resume_off();
+
 	pwrdm_post_transition();
 
 	return 0;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 10/20] ARM: OMAP4: PM: save/restore all CM1/2 settings in OFF mode
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (8 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 09/20] ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 11/20] ARM: OMAP4: PM: Add SAR backup support towards device OFF Tero Kristo
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Rajendra Nayak <rnayak@ti.com>

Restore all CM1/2 module registers as they are lost in OFF mode.

[nm at ti.com: minor clean ups]
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Axel Haslam <axelhaslam@gmail.com>
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/cm44xx.c              |  328 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/cm44xx.h              |    2 +
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |    5 +-
 3 files changed, 334 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c
index 535d66e..1958808 100644
--- a/arch/arm/mach-omap2/cm44xx.c
+++ b/arch/arm/mach-omap2/cm44xx.c
@@ -21,8 +21,11 @@
 #include "iomap.h"
 #include "common.h"
 #include "cm.h"
+#include "cm44xx.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
+#include "cminst44xx.h"
+#include "prcm44xx.h"
 #include "cm-regbits-44xx.h"
 
 /* CM1 hardware module low-level functions */
@@ -50,3 +53,328 @@ void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg)
 {
 	__raw_writel(val, OMAP44XX_CM2_REGADDR(inst, reg));
 }
+
+#define MAX_CM_REGISTERS 51
+
+struct omap4_cm_reg {
+	u16 offset;
+	u32 val;
+};
+
+struct omap4_cm_regs {
+	u16 mod_off;
+	u16 no_reg;
+	struct omap4_cm_reg reg[MAX_CM_REGISTERS];
+};
+
+static struct omap4_cm_regs cm1_regs[] = {
+	/* OMAP4430_CM1_OCP_SOCKET_MOD */
+	{ .mod_off = OMAP4430_CM1_OCP_SOCKET_INST, .no_reg = 1,
+		{
+			{ OMAP4_CM_CM1_PROFILING_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM1_CKGEN_MOD */
+	{ .mod_off = OMAP4430_CM1_CKGEN_INST, .no_reg = 4,
+		{
+			{ OMAP4_CM_CLKSEL_CORE_OFFSET },
+			{ OMAP4_CM_CLKSEL_ABE_OFFSET },
+			{ OMAP4_CM_DLL_CTRL_OFFSET },
+			{ OMAP4_CM_DYN_DEP_PRESCAL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM1_MPU_MOD */
+	{ .mod_off = OMAP4430_CM1_MPU_INST, .no_reg = 4,
+		{
+			{ OMAP4_CM_MPU_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_MPU_STATICDEP_OFFSET },
+			{ OMAP4_CM_MPU_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM1_TESLA_MOD */
+	{ .mod_off = OMAP4430_CM1_TESLA_INST, .no_reg = 4,
+		{
+			{ OMAP4_CM_TESLA_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_TESLA_STATICDEP_OFFSET },
+			{ OMAP4_CM_TESLA_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM1_ABE_MOD */
+	{ .mod_off = OMAP4430_CM1_ABE_INST, .no_reg = 15,
+		{
+			{ OMAP4_CM1_ABE_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_SLIMBUS_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET },
+			{ OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET }
+		},
+	},
+};
+
+static struct omap4_cm_regs cm2_regs[] = {
+	/* OMAP4430_CM2_OCP_SOCKET_MOD */
+	{ .mod_off = OMAP4430_CM2_OCP_SOCKET_INST, .no_reg = 1,
+		{
+			{ OMAP4_CM_CM2_PROFILING_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_CKGEN_MOD */
+	{ .mod_off = OMAP4430_CM2_CKGEN_INST, .no_reg = 12,
+		{
+			{ OMAP4_CM_CLKSEL_DUCATI_ISS_ROOT_OFFSET },
+			{ OMAP4_CM_CLKSEL_USB_60MHZ_OFFSET },
+			{ OMAP4_CM_SCALE_FCLK_OFFSET },
+			{ OMAP4_CM_CORE_DVFS_PERF1_OFFSET },
+			{ OMAP4_CM_CORE_DVFS_PERF2_OFFSET },
+			{ OMAP4_CM_CORE_DVFS_PERF3_OFFSET },
+			{ OMAP4_CM_CORE_DVFS_PERF4_OFFSET },
+			{ OMAP4_CM_CORE_DVFS_CURRENT_OFFSET },
+			{ OMAP4_CM_IVA_DVFS_PERF_TESLA_OFFSET },
+			{ OMAP4_CM_IVA_DVFS_PERF_IVAHD_OFFSET },
+			{ OMAP4_CM_IVA_DVFS_PERF_ABE_OFFSET },
+			{ OMAP4_CM_IVA_DVFS_CURRENT_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_ALWAYS_ON_MOD */
+	{ .mod_off = OMAP4430_CM2_ALWAYS_ON_INST, .no_reg = 6,
+		{
+			{ OMAP4_CM_ALWON_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_ALWON_MDMINTC_CLKCTRL_OFFSET },
+			{ OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET },
+			{ OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET },
+			{ OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET },
+			{ OMAP4_CM_ALWON_USBPHY_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_CORE_MOD */
+	{ .mod_off = OMAP4430_CM2_CORE_INST, .no_reg = 41,
+		{
+			{ OMAP4_CM_L3_1_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L3_1_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3_2_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L3_2_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3_2_GPMC_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3_2_OCMC_RAM_CLKCTRL_OFFSET },
+			{ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_DUCATI_STATICDEP_OFFSET },
+			{ OMAP4_CM_DUCATI_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET },
+			{ OMAP4_CM_SDMA_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_SDMA_STATICDEP_OFFSET },
+			{ OMAP4_CM_SDMA_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_SDMA_SDMA_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_EMIF_FW_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_EMIF_1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_EMIF_2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_DLL_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_EMIF_H1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_EMIF_H2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_MEMIF_DLL_H_CLKCTRL_OFFSET },
+			{ OMAP4_CM_D2D_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_D2D_STATICDEP_OFFSET },
+			{ OMAP4_CM_D2D_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_D2D_SAD2D_CLKCTRL_OFFSET },
+			{ OMAP4_CM_D2D_MODEM_ICR_CLKCTRL_OFFSET },
+			{ OMAP4_CM_D2D_SAD2D_FW_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4CFG_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L4CFG_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4CFG_HW_SEM_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4CFG_SAR_ROM_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INSTR_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_IVAHD_MOD */
+	{ .mod_off = OMAP4430_CM2_IVAHD_INST, .no_reg = 5,
+		{
+			{ OMAP4_CM_IVAHD_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_IVAHD_STATICDEP_OFFSET },
+			{ OMAP4_CM_IVAHD_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET },
+			{ OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_CAM_MOD */
+	{ .mod_off = OMAP4430_CM2_CAM_INST, .no_reg = 5,
+		{
+			{ OMAP4_CM_CAM_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_CAM_STATICDEP_OFFSET },
+			{ OMAP4_CM_CAM_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET },
+			{ OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_DSS_MOD */
+	{ .mod_off = OMAP4430_CM2_DSS_INST, .no_reg = 5,
+		{
+			{ OMAP4_CM_DSS_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_DSS_STATICDEP_OFFSET },
+			{ OMAP4_CM_DSS_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET },
+			{ OMAP4_CM_DSS_DEISS_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_GFX_MOD */
+	{ .mod_off = OMAP4430_CM2_GFX_INST, .no_reg = 4,
+		{
+			{ OMAP4_CM_GFX_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_GFX_STATICDEP_OFFSET },
+			{ OMAP4_CM_GFX_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_L3INIT_MOD */
+	{ .mod_off = OMAP4430_CM2_L3INIT_INST, .no_reg = 20,
+		{
+			{ OMAP4_CM_L3INIT_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_STATICDEP_OFFSET },
+			{ OMAP4_CM_L3INIT_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_HSI_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_UNIPRO1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_P1500_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_EMAC_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_SATA_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_TPPSS_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_PCIESS_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_CCPTX_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_XHPI_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_MMC6_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_USB_HOST_FS_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_L4PER_MOD */
+	{ .mod_off = OMAP4430_CM2_L4PER_INST, .no_reg = 51,
+		{
+			{ OMAP4_CM_L4PER_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_L4PER_ADC_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_ELM_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_HECC1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_HECC2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCASP2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCASP3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MGATE_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MSPROHG_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_SLIMBUS2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4PER_I2C5_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_STATICDEP_OFFSET },
+			{ OMAP4_CM_L4SEC_DYNAMICDEP_OFFSET },
+			{ OMAP4_CM_L4SEC_AES1_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_AES2_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_DES3DES_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_PKAEIP29_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_RNG_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_SHA2MD51_CLKCTRL_OFFSET },
+			{ OMAP4_CM_L4SEC_CRYPTODMA_CLKCTRL_OFFSET }
+		},
+	},
+	/* OMAP4430_CM2_CEFUSE_MOD */
+	{ .mod_off = OMAP4430_CM2_CEFUSE_INST, .no_reg = 2,
+		{
+			{ OMAP4_CM_CEFUSE_CLKSTCTRL_OFFSET },
+			{ OMAP4_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET }
+		},
+	},
+};
+
+static void omap4_cm_part_prepare_off(u32 part, struct omap4_cm_regs *cm_reg,
+				      int size)
+{
+	u32 i, j;
+
+	for (i = 0; i < size; i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(part,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm_part_resume_off(u32 part, struct omap4_cm_regs *cm_reg,
+				     int size)
+{
+	u32 i, j;
+
+	for (i = 0; i < size; i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    part,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}
+
+void omap4_cm_prepare_off(void)
+{
+	omap4_cm_part_prepare_off(OMAP4430_CM1_PARTITION, cm1_regs,
+				  ARRAY_SIZE(cm1_regs));
+	omap4_cm_part_prepare_off(OMAP4430_CM2_PARTITION, cm2_regs,
+				  ARRAY_SIZE(cm2_regs));
+}
+
+void omap4_cm_resume_off(void)
+{
+	omap4_cm_part_resume_off(OMAP4430_CM1_PARTITION, cm1_regs,
+				 ARRAY_SIZE(cm1_regs));
+	omap4_cm_part_resume_off(OMAP4430_CM2_PARTITION, cm2_regs,
+				 ARRAY_SIZE(cm2_regs));
+}
diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h
index 5fba0fa..b3b0f21 100644
--- a/arch/arm/mach-omap2/cm44xx.h
+++ b/arch/arm/mach-omap2/cm44xx.h
@@ -24,6 +24,8 @@
 #define OMAP4_CM_STATICDEP				0x0004
 
 #ifndef __ASSEMBLER__
+extern void omap4_cm_prepare_off(void);
+extern void omap4_cm_resume_off(void);
 extern void omap4_dpll_prepare_off(void);
 extern void omap4_dpll_resume_off(void);
 #endif
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 805ee38..f1a1db0 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -267,6 +267,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 */
 	mpuss_clear_prev_logic_pwrst();
 	if (pwrdm_read_next_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF) {
+		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
 		save_state = 3;
 	} else if (pwrdm_read_next_func_pwrst(mpuss_pd) ==
@@ -295,8 +296,10 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_FUNC_PWRST_ON);
 
-	if (pwrdm_read_prev_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF)
+	if (pwrdm_read_prev_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF) {
 		omap4_dpll_resume_off();
+		omap4_cm_resume_off();
+	}
 
 	pwrdm_post_transition();
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 11/20] ARM: OMAP4: PM: Add SAR backup support towards device OFF
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (9 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 10/20] ARM: OMAP4: PM: save/restore all CM1/2 " Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 12/20] ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA Tero Kristo
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

Most of the device register contents are lost during device off. To
resume properly from this, a special memory area called SAR RAM is
maintained during device off, and its contents are restored to HW
registers during wakeup. The register layout is fixed in SAR RAM.
SAR is split into 4 banks with different privilege accesses based
on device type:

 ---------------------------------------------------------------
 Access mode            Bank    Address Range
 ---------------------------------------------------------------
 HS/GP : Public         1       0x4A32_6000 - 0x4A32_6FFF (4kB)
 HS/GP : Public         2       0x4A32_7000 - 0x4A32_73FF (1kB)

 HS/EMU : Secured
 GP : Public            3       0x4A32_8000 - 0x4A32_87FF (2kB)

 HS/GP :Secure
 write once.            4       0x4A32_9000 - 0x4A32_93FF (1kB)
 ---------------------------------------------------------------

The save process is done entirely by software and restore is done by
hardware using the auto-restore feature. The restore feature is enabled
by default and cannot be disabled. The software must save the data
to be restored in a dedicated location in SAR RAM.

IO address -> SAR RAM layout is generated during init time from the
contents of the SAR ROM. An algorithm is executed which parses the
contents of each SAR ROM entry, and creates IO -> SAR RAM mapping
based on this. This mapping is then later used before each entry
to device off to save the IO registers to the SAR RAM.

Original code written by Santosh Shilimkar <santosh.shilimkar@ti.com>,
updated with the auto generate feature by Tero Kristo <t-kristo@ti.com>.
Contributions / cleanups to the original code were received from
Rajeev Kulkarni <rajeev@ti.com>,
Nishanth Menon <nm@ti.com>,
Axel Haslam <axelhaslam@gmail.com> and
Avinash.H.M <avinashhm@ti.com>.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/Makefile               |    2 +-
 arch/arm/mach-omap2/cm1_44xx.h             |    2 +
 arch/arm/mach-omap2/cm2_44xx.h             |    2 +
 arch/arm/mach-omap2/omap-mpuss-lowpower.c  |    6 +
 arch/arm/mach-omap2/omap-sar.c             |  623 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/omap4-common.c         |   28 --
 arch/arm/mach-omap2/omap4-sar-layout.h     |   26 ++
 arch/arm/mach-omap2/pm.h                   |    8 +
 arch/arm/plat-omap/include/plat/omap44xx.h |    6 +
 9 files changed, 674 insertions(+), 29 deletions(-)
 create mode 100644 arch/arm/mach-omap2/omap-sar.c

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index fa742f3..f7ca602 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
 obj-$(CONFIG_SMP)			+= omap-smp.o omap-headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= omap-hotplug.o
 obj-$(CONFIG_ARCH_OMAP4)		+= omap4-common.o omap-wakeupgen.o
-obj-$(CONFIG_ARCH_OMAP4)		+= sleep44xx.o
+obj-$(CONFIG_ARCH_OMAP4)		+= sleep44xx.o omap-sar.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_omap-headsmp.o			:=-Wa,-march=armv7-a$(plus_sec)
diff --git a/arch/arm/mach-omap2/cm1_44xx.h b/arch/arm/mach-omap2/cm1_44xx.h
index 1bc00dc..c21b660 100644
--- a/arch/arm/mach-omap2/cm1_44xx.h
+++ b/arch/arm/mach-omap2/cm1_44xx.h
@@ -218,8 +218,10 @@
 #define OMAP4430_CM1_ABE_WDT3_CLKCTRL			OMAP44XX_CM1_REGADDR(OMAP4430_CM1_ABE_INST, 0x0088)
 
 /* Function prototypes */
+#ifndef __ASSEMBLER__
 extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx);
 extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx);
 extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
+#endif
 
 #endif
diff --git a/arch/arm/mach-omap2/cm2_44xx.h b/arch/arm/mach-omap2/cm2_44xx.h
index b9de72d..3e8871e 100644
--- a/arch/arm/mach-omap2/cm2_44xx.h
+++ b/arch/arm/mach-omap2/cm2_44xx.h
@@ -450,8 +450,10 @@
 #define OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_INST, 0x0020)
 
 /* Function prototypes */
+#ifndef __ASSEMBLER__
 extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx);
 extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx);
 extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
+#endif
 
 #endif
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index f1a1db0..da84339 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -234,6 +234,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 {
 	unsigned int save_state = 0;
 	unsigned int wakeup_cpu;
+	int ret;
 
 	if (omap_rev() == OMAP4430_REV_ES1_0)
 		return -ENXIO;
@@ -267,6 +268,10 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 */
 	mpuss_clear_prev_logic_pwrst();
 	if (pwrdm_read_next_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF) {
+		/* Save the device context to SAR RAM */
+		ret = omap_sar_save();
+		if (ret)
+			goto sar_save_failed;
 		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
 		save_state = 3;
@@ -301,6 +306,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 		omap4_cm_resume_off();
 	}
 
+sar_save_failed:
 	pwrdm_post_transition();
 
 	return 0;
diff --git a/arch/arm/mach-omap2/omap-sar.c b/arch/arm/mach-omap2/omap-sar.c
new file mode 100644
index 0000000..548454e
--- /dev/null
+++ b/arch/arm/mach-omap2/omap-sar.c
@@ -0,0 +1,623 @@
+/*
+ * OMAP4 Save Restore source file
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include "iomap.h"
+#include "pm.h"
+#include "clockdomain.h"
+
+#include "omap4-sar-layout.h"
+#include "cm-regbits-44xx.h"
+#include "cm-regbits-34xx.h"
+#include "prcm44xx.h"
+#include "cminst44xx.h"
+
+static void __iomem *sar_ram_base;
+static struct powerdomain *l3init_pwrdm;
+	static struct clockdomain *l3init_clkdm;
+static struct clk *usb_host_ck, *usb_tll_ck;
+
+/**
+ * struct sar_ram_entry - SAR RAM layout descriptor
+ * @io_base: IO base address for the entry
+ * @offset: IO offset from @io_base
+ * @size: size of entry in words, size=0 marks end of descriptor array
+ * @ram_addr: SAR RAM address to store the data to
+ */
+struct sar_ram_entry {
+	void __iomem *io_base;
+	u32 offset;
+	u32 size;
+	u32 ram_addr;
+};
+
+/**
+ * struct sar_overwrite_entry - SAR RAM overwrite descriptor
+ * @reg_addr: register address
+ * @sar_offset: offset in SAR RAM
+ * @valid: whether data for this entry was found or not from SAR ROM
+ */
+struct sar_overwrite_entry {
+	u32 reg_addr;
+	u32 sar_offset;
+	bool valid;
+};
+
+enum {
+	MEMIF_CLKSTCTRL_IDX,
+	SHADOW_FREQ_CFG2_IDX,
+	SHADOW_FREQ_CFG1_IDX,
+	MEMIF_CLKSTCTRL_2_IDX,
+	HSUSBHOST_CLKCTRL_IDX,
+	HSUSBHOST_CLKCTRL_2_IDX,
+	L3INIT_CLKSTCTRL_IDX,
+	OW_IDX_SIZE
+};
+
+static struct sar_ram_entry *sar_ram_layout[3];
+static struct sar_overwrite_entry *sar_overwrite_data;
+
+static struct sar_overwrite_entry omap4_sar_overwrite_data[OW_IDX_SIZE] = {
+	[MEMIF_CLKSTCTRL_IDX] = { .reg_addr = 0x4a009e0c },
+	[SHADOW_FREQ_CFG2_IDX] = { .reg_addr = 0x4a004e2c },
+	[SHADOW_FREQ_CFG1_IDX] = { .reg_addr = 0x4a004e30 },
+	[MEMIF_CLKSTCTRL_2_IDX] = { .reg_addr = 0x4a009e0c },
+	[HSUSBHOST_CLKCTRL_IDX] = { .reg_addr = 0x4a009e54 },
+	[HSUSBHOST_CLKCTRL_2_IDX] = { .reg_addr = 0x4a009e54 },
+	[L3INIT_CLKSTCTRL_IDX] = { .reg_addr = 0x4a009300 },
+};
+
+/**
+ * check_overwrite_data - update matching SAR overwrite entry
+ * @io_addr: IO address of the entry to lookup
+ * @ram_addr: SAR RAM address of the entry to update
+ * @size: size of the entry in words
+ *
+ * Checks a single SAR RAM entry against existing SAR RAM overwrite data.
+ * If a matching overwrite location is found, update the pointers for
+ * that entry. As each SAR RAM entry is of @size, the function must
+ * go over the whole entry area in a for loop to find any possible
+ * matching locations.
+ */
+static void check_overwrite_data(u32 io_addr, u32 ram_addr, int size)
+{
+	int i;
+
+	while (size) {
+		for (i = 0; i < OW_IDX_SIZE; i++) {
+			if (sar_overwrite_data[i].reg_addr == io_addr &&
+			    !sar_overwrite_data[i].valid) {
+				sar_overwrite_data[i].sar_offset = ram_addr;
+				sar_overwrite_data[i].valid = true;
+				break;
+			}
+		}
+		size--;
+		io_addr += 4;
+		ram_addr += 4;
+	}
+}
+
+/**
+ * omap_sar_save - saves a SAR RAM layout
+ * @entry: first descriptor for the layout to save
+ *
+ * common routine to save the registers to SAR RAM with the
+ * given parameters
+ */
+static void sar_save(struct sar_ram_entry *entry)
+{
+	u32 reg_val, size, offset;
+	void __iomem *reg_read_addr, *sar_wr_addr;
+
+	while (entry->size) {
+		size = entry->size;
+		reg_read_addr = entry->io_base + entry->offset;
+		sar_wr_addr = sar_ram_base + entry->ram_addr;
+		for (offset = 0; offset < size * 4; offset += 4) {
+			reg_val = __raw_readl(reg_read_addr + offset);
+			__raw_writel(reg_val, sar_wr_addr + offset);
+		}
+		entry++;
+	}
+}
+
+/**
+ * save_sar_bank3 - save SAR RAM bank 3
+ *
+ * Saves SAR RAM bank 3, this contains static data and should be saved
+ * only once during boot.
+ */
+static void save_sar_bank3(void)
+{
+	struct clockdomain *l4_secure_clkdm;
+
+	/*
+	 * Not supported on ES1.0 silicon
+	 */
+	if (omap_rev() == OMAP4430_REV_ES1_0) {
+		WARN_ONCE(1, "omap4: SAR backup not supported on ES1.0 ..\n");
+		return;
+	}
+
+	l4_secure_clkdm = clkdm_lookup("l4_secure_clkdm");
+	clkdm_wakeup(l4_secure_clkdm);
+
+	sar_save(sar_ram_layout[2]);
+
+	clkdm_allow_idle(l4_secure_clkdm);
+}
+
+/**
+ * omap4_sar_not_accessible - checks if all SAR IO areas are accessible
+ *
+ * Check if all SAR RAM IO locations are accessible or not. Namely,
+ * USB host and TLL modules should be idle.
+ */
+static int omap4_sar_not_accessible(void)
+{
+	u32 usbhost_state, usbtll_state;
+
+	/*
+	 * Make sure that USB host and TLL modules are not
+	 * enabled before attempting to save the context
+	 * registers, otherwise this will trigger an exception.
+	 */
+	usbhost_state = omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+				OMAP4430_CM2_L3INIT_INST,
+				OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET);
+	usbhost_state &= (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK);
+
+	usbtll_state = omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+				OMAP4430_CM2_L3INIT_INST,
+				OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET);
+	usbtll_state &= OMAP4430_IDLEST_MASK;
+
+	if ((usbhost_state == (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK)) &&
+	    (usbtll_state == (OMAP4430_IDLEST_MASK)))
+		return 0;
+	else
+		return -EBUSY;
+}
+
+/**
+ * omap_sar_overwrite :
+ * This API overwrites some of the SAR locations as a special cases
+ * The register content to be saved can be the register value before
+ * going into OFF-mode or a value that is required on wake up. This means
+ * that the restored register value can be different from the last value
+ * of the register before going into OFF-mode
+ *	- CM1 and CM2 configuration
+ *		Bits 0 of the CM_SHADOW_FREQ_CONFIG1 regiser and the
+ *		CM_SHADOW_FREQ_CONFIG2 register are self-clearing and must
+ *		 be set@restore time. Thus, these data must always be
+ *		overwritten in the SAR RAM.
+ *	- Because USBHOSTHS and USBTLL restore needs a particular
+ *		sequencing, the software must overwrite data read from
+ *		the following registers implied in phase2a and phase 2b
+ */
+static void omap_sar_overwrite(void)
+{
+	u32 val = 0;
+	u32 offset = 0;
+
+	if (sar_overwrite_data[MEMIF_CLKSTCTRL_IDX].valid)
+		__raw_writel(0x2, sar_ram_base +
+			sar_overwrite_data[MEMIF_CLKSTCTRL_IDX].sar_offset);
+
+	if (sar_overwrite_data[SHADOW_FREQ_CFG1_IDX].valid) {
+		offset = sar_overwrite_data[SHADOW_FREQ_CFG1_IDX].sar_offset;
+		val = __raw_readl(sar_ram_base + offset);
+		val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT;
+		val &= ~OMAP4430_DLL_OVERRIDE_2_2_MASK;
+		__raw_writel(val, sar_ram_base + offset);
+	}
+
+	if (sar_overwrite_data[SHADOW_FREQ_CFG2_IDX].valid) {
+		offset = sar_overwrite_data[SHADOW_FREQ_CFG2_IDX].sar_offset;
+		val = __raw_readl(sar_ram_base + offset);
+		/*
+		 * FIXME: Implement FREQ UPDATE for L#/M5 before enabling
+		 * val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT;
+		 */
+		__raw_writel(val, sar_ram_base + offset);
+	}
+
+	if (sar_overwrite_data[MEMIF_CLKSTCTRL_2_IDX].valid)
+		__raw_writel(0x3, sar_ram_base +
+			sar_overwrite_data[MEMIF_CLKSTCTRL_2_IDX].sar_offset);
+
+	if (sar_overwrite_data[HSUSBHOST_CLKCTRL_IDX].valid) {
+		offset = sar_overwrite_data[HSUSBHOST_CLKCTRL_IDX].sar_offset;
+
+		/* Overwriting Phase2a data to be restored */
+		/* CM_L3INIT_USB_HOST_CLKCTRL: SAR_MODE = 1, MODULEMODE = 2 */
+		__raw_writel(OMAP4430_SAR_MODE_MASK | 0x2,
+			sar_ram_base + offset);
+		/* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 1, MODULEMODE = 1 */
+		__raw_writel(OMAP4430_SAR_MODE_MASK | 0x1,
+			sar_ram_base + offset + 4);
+		/*
+		 * CM2 CM_SDMA_STATICDEP : Enable static depedency for
+		 * SAR modules
+		 */
+		__raw_writel(OMAP4430_L4WKUP_STATDEP_MASK |
+			     OMAP4430_L4CFG_STATDEP_MASK |
+			     OMAP4430_L3INIT_STATDEP_MASK |
+			     OMAP4430_L3_1_STATDEP_MASK |
+			     OMAP4430_L3_2_STATDEP_MASK |
+			     OMAP4430_ABE_STATDEP_MASK,
+			     sar_ram_base + offset + 8);
+	}
+
+	if (sar_overwrite_data[HSUSBHOST_CLKCTRL_2_IDX].valid) {
+		offset = sar_overwrite_data[HSUSBHOST_CLKCTRL_2_IDX].sar_offset;
+
+		/* Overwriting Phase2b data to be restored */
+		/* CM_L3INIT_USB_HOST_CLKCTRL: SAR_MODE = 0, MODULEMODE = 0 */
+		val = __raw_readl(OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL);
+		val &= (OMAP4430_CLKSEL_UTMI_P1_MASK |
+			OMAP4430_CLKSEL_UTMI_P2_MASK);
+		__raw_writel(val, sar_ram_base + offset);
+		/* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 0, MODULEMODE = 0 */
+		__raw_writel(0, sar_ram_base + offset + 4);
+		/* CM2 CM_SDMA_STATICDEP : Clear the static depedency */
+		__raw_writel(OMAP4430_L3_2_STATDEP_MASK,
+			     sar_ram_base + offset + 8);
+	}
+
+	if (sar_overwrite_data[L3INIT_CLKSTCTRL_IDX].valid) {
+		offset = sar_overwrite_data[L3INIT_CLKSTCTRL_IDX].sar_offset;
+
+		/*
+		 * Set CM_L3INIT_CLKSTRCTRL to FORCE_SLEEP, it is enabled
+		 * during SAR save and gets incorrect value of FORCE_WAKEUP.
+		 */
+		val = __raw_readl(sar_ram_base + offset);
+		val &= ~(OMAP4430_CLKTRCTRL_MASK);
+		val |= OMAP34XX_CLKSTCTRL_FORCE_SLEEP;
+		__raw_writel(val, sar_ram_base + offset);
+	}
+
+	/* readback to ensure data reaches to SAR RAM */
+	barrier();
+	val = __raw_readl(sar_ram_base + offset);
+}
+
+/**
+ * omap_sar_save - save sar context to SAR RAM
+ *
+ * Save the context to SAR_RAM1 and SAR_RAM2 as per the generated SAR
+ * RAM layouts (sar_ram_layout[0] / [1]) and overwrite parts of the
+ * area according to the overwrite data. This must be done before
+ * attempting device off mode.
+ */
+int omap_sar_save(void)
+{
+	if (omap4_sar_not_accessible()) {
+		pr_debug("%s: USB SAR CNTX registers are not accessible!\n",
+			__func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * SAR bits and clocks needs to be enabled
+	 */
+	clkdm_wakeup(l3init_clkdm);
+	pwrdm_enable_hdwr_sar(l3init_pwrdm);
+	clk_enable(usb_host_ck);
+	clk_enable(usb_tll_ck);
+
+	/* Save SAR BANK1 */
+	sar_save(sar_ram_layout[0]);
+
+	clk_disable(usb_host_ck);
+	clk_disable(usb_tll_ck);
+	pwrdm_disable_hdwr_sar(l3init_pwrdm);
+	clkdm_allow_idle(l3init_clkdm);
+
+	/* Save SAR BANK2 */
+	sar_save(sar_ram_layout[1]);
+
+	omap_sar_overwrite();
+
+	return 0;
+}
+
+void __iomem *omap4_get_sar_ram_base(void)
+{
+	return sar_ram_base;
+}
+
+/*
+ * SAR ROM phases correspond to different restore phases executed
+ * according to TRM chapter 16.4.21.4. "SAR ROM". Different phases
+ * are executed according to different types of wakeups, and at
+ * different points of wakeup chain. All the data must be stored
+ * for the restore to be successful before device off entry. The
+ * values in this array are offsets from the SAR ROM base address.
+ */
+static const u32 sar_rom_phases[] = {
+	0, 0x30, 0x60
+};
+
+/**
+ * struct sar_module - SAR IO module declarations
+ * @io_base: IO base pointer for the module
+ * @base: base physical address for the module
+ * @size: size of the module
+ * @invalid: flag for marking modules invalid for certain architectures
+ */
+struct sar_module {
+	void __iomem *io_base;
+	u32 base;
+	u32 size;
+	bool invalid;
+};
+
+static struct sar_module *sar_modules;
+
+/**
+ * sar_ioremap_modules - map the IO address space for all modules
+ *
+ * Maps the whole IO address space required by SAR mechanism for
+ * reading the registers from IO address space.
+ */
+static void sar_ioremap_modules(void)
+{
+	struct sar_module *mod;
+
+	mod = sar_modules;
+
+	while (mod->base) {
+		if (!mod->invalid) {
+			mod->io_base = ioremap(mod->base, mod->size);
+			if (!mod->io_base)
+				pr_err("%s: ioremap failed for %08x[%08x]\n",
+					__func__, mod->base, mod->size);
+			WARN_ON(!mod->io_base);
+		}
+		mod++;
+	}
+}
+
+/**
+ * set_sar_io_addr - route SAR RAM entry to SAR IO module
+ * @entry: SAR RAM entry to route
+ * @addr: target IO address
+ *
+ * Scans available SAR IO modules for a matching one. If a match is
+ * found, sets the entry base address to point the IO address space
+ * and calculates the address offset from the beginning of the module.
+ * Returns 0 if a matching IO module was found, -EINVAL otherwise.
+ */
+static int set_sar_io_addr(struct sar_ram_entry *entry, u32 addr)
+{
+	struct sar_module *mod;
+
+	mod = sar_modules;
+
+	while (mod->base) {
+		if (addr >= mod->base && addr <= mod->base + mod->size) {
+			if (mod->invalid)
+				break;
+			entry->io_base = mod->io_base;
+			entry->offset = addr - mod->base;
+			return 0;
+		}
+		mod++;
+	}
+	pr_warn("%s: no matching sar_module for %08x\n", __func__, addr);
+	return -EINVAL;
+}
+
+/**
+ * sar_layout_generate - generates SAR RAM layout based on SAR ROM contents
+ *
+ * This function parses the contents of the SAR ROM to generate SAR RAM
+ * layout entries. SAR ROM consists of following entries:
+ *      u32 next        : pointer to next element on ROM
+ *      u32 size        : number of words to restore
+ *      u32 ram_address : SAR RAM address to restore from
+ *      u32 io_address  : IO address to write SAR RAM contents to
+ *
+ * The function parses each SAR ROM entry, checks the validity of pointers
+ * to both IO and SAR RAM, and adds the entry to the list if it is valid.
+ * After adding the entry, next ROM entry is parsed, unless the target
+ * pointer is outside of SAR ROM area which indicates end of restore chain.
+ * Returns 0 on success, negative error value otherwise.
+ */
+static int sar_layout_generate(void)
+{
+	int phase;
+	void __iomem *sarrom;
+	u32 rombase, romend, rambase, ramend;
+	u32 offset, next;
+	u16 size;
+	u32 ram_addr, io_addr;
+	void *sarram;
+	struct sar_ram_entry *entry[3];
+	int bank;
+	int ret = 0;
+
+	pr_info("generating sar_ram layout...\n");
+
+	rombase = OMAP44XX_SAR_ROM_BASE;
+	romend = rombase + SZ_8K;
+	rambase = OMAP44XX_SAR_RAM_BASE;
+	ramend = rambase + SAR_BANK4_OFFSET - 1;
+
+	sarrom = ioremap(rombase, SZ_8K);
+
+	/*
+	 * Allocate temporary memory for sar ram layout. The amount
+	 * allocated is exaggerated to make sure everything fits in,
+	 * this memory is freed once SAR RAM layout generation is
+	 * completed and actual sizes are known
+	 */
+	sarram = kmalloc(SAR_BANK4_OFFSET, GFP_KERNEL);
+	for (bank = 0; bank < 3; bank++)
+		entry[bank] = sarram + SAR_BANK2_OFFSET * bank;
+
+	/* Go through each SAR ROM restore phase */
+	for (phase = 0; phase < ARRAY_SIZE(sar_rom_phases); phase++) {
+		offset = sar_rom_phases[phase];
+
+		while (1) {
+			next = __raw_readl(sarrom + offset);
+			size = __raw_readl(sarrom + offset + 4) & 0xffff;
+			ram_addr = __raw_readl(sarrom + offset + 8);
+			io_addr = __raw_readl(sarrom + offset + 12);
+
+			if (ram_addr >= rambase && ram_addr <= ramend) {
+				/* Valid ram address, add entry */
+				ram_addr -= rambase;
+
+				/* Calculate which bank we are using */
+				bank = ram_addr / SAR_BANK2_OFFSET;
+
+				if (!set_sar_io_addr(entry[bank], io_addr)) {
+					entry[bank]->size = size;
+					entry[bank]->ram_addr = ram_addr;
+					check_overwrite_data(io_addr, ram_addr,
+						size);
+					entry[bank]++;
+				}
+			}
+
+			/*
+			 * If pointer to next SAR ROM address is invalid,
+			 * stop. Indicates end of restore phase.
+			 */
+			if (next < rombase || next > romend)
+				break;
+
+			offset = next - rombase;
+		}
+	}
+
+	/* Copy SAR RAM entry data to permanent location */
+	for (bank = 0; bank < 3; bank++) {
+		size = (u32)entry[bank] -
+			(u32)(sarram + SAR_BANK2_OFFSET * bank);
+		sar_ram_layout[bank] = kmalloc(size +
+			sizeof(struct sar_ram_entry), GFP_KERNEL);
+		if (!sar_ram_layout[bank]) {
+			pr_err("%s: kmalloc failed\n", __func__);
+			goto cleanup;
+		}
+		memcpy(sar_ram_layout[bank], sarram + SAR_BANK2_OFFSET * bank,
+			size);
+		memset((void *)sar_ram_layout[bank] + size, 0,
+			sizeof(struct sar_ram_entry));
+		entry[bank] = sar_ram_layout[bank];
+	}
+
+cleanup:
+	kfree(sarram);
+	iounmap(sarrom);
+	pr_info("sar ram layout created\n");
+	return ret;
+}
+
+/*
+ * SAR IO module mapping. This is used to access the hardware registers
+ * during SAR save.
+ */
+static struct sar_module omap44xx_sar_modules[] = {
+	{ .base = OMAP44XX_EMIF1_BASE, .size = SZ_1M },
+	{ .base = OMAP44XX_EMIF2_BASE, .size = SZ_1M },
+	{ .base = OMAP44XX_DMM_BASE, .size = SZ_1M },
+	{ .base = OMAP4430_CM1_BASE, .size = SZ_8K },
+	{ .base = OMAP4430_CM2_BASE, .size = SZ_8K },
+	{ .base = OMAP44XX_C2C_BASE, .size = SZ_1M },
+	{ .base = OMAP443X_CTRL_BASE, .size = SZ_4K },
+	{ .base = L3_44XX_BASE_CLK1, .size = SZ_1M },
+	{ .base = L3_44XX_BASE_CLK2, .size = SZ_1M },
+	{ .base = L3_44XX_BASE_CLK3, .size = SZ_1M },
+	{ .base = OMAP44XX_USBTLL_BASE, .size = SZ_1M },
+	{ .base = OMAP44XX_UHH_CONFIG_BASE, .size = SZ_1M },
+	{ .base = L4_44XX_PHYS, .size = SZ_4M },
+	{ .base = L4_PER_44XX_PHYS, .size = SZ_4M },
+	{ .base = 0 },
+};
+
+/**
+ * omap4_sar_ram_init - initializes SAR save mechanism
+ *
+ * This function allocates the IO maps, generates the SAR RAM layout
+ * entries, detects the overwrite locations and stores the once per
+ * boot type data (sar_bank3). Also L3INIT clockdomain / clocks
+ * are allocated, which are needed during SAR save.
+ */
+static int __init omap4_sar_ram_init(void)
+{
+	/*
+	 * To avoid code running on other OMAPs in
+	 * multi-omap builds
+	 */
+	if (!cpu_is_omap44xx())
+		return -ENODEV;
+
+	/*
+	 * Static mapping, never released Actual SAR area used is 8K it's
+	 * spaced over 16K address with some part is reserved.
+	 */
+	sar_ram_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K);
+	if (WARN_ON(!sar_ram_base))
+		return -ENOMEM;
+
+	sar_modules = omap44xx_sar_modules;
+	sar_overwrite_data = omap4_sar_overwrite_data;
+
+	sar_ioremap_modules();
+
+	sar_layout_generate();
+
+	/*
+	 * SAR BANK3 contains all firewall settings and it's saved through
+	 * secure API on HS device. On GP device these registers are
+	 * meaningless but still needs to be saved. Otherwise Auto-restore
+	 * phase DMA takes an abort. Hence save these conents only once
+	 * in init to avoid the issue while waking up from device OFF
+	 */
+	if (omap_type() == OMAP2_DEVICE_TYPE_GP)
+		save_sar_bank3();
+
+	/*
+	 * L3INIT PD and clocks are needed for SAR save phase
+	 */
+	l3init_pwrdm = pwrdm_lookup("l3init_pwrdm");
+	if (!l3init_pwrdm)
+		pr_err("Failed to get l3init_pwrdm\n");
+
+	l3init_clkdm = clkdm_lookup("l3_init_clkdm");
+	if (!l3init_clkdm)
+		pr_err("Failed to get l3_init_clkdm\n");
+
+	usb_host_ck = clk_get_sys("usbhs_omap", "hs_fck");
+	if (IS_ERR(usb_host_ck))
+		pr_err("Could not get usb_host_ck\n");
+
+	usb_tll_ck = clk_get_sys("usbhs_omap", "usbtll_ick");
+	if (IS_ERR(usb_tll_ck))
+		pr_err("Could not get usb_tll_ck\n");
+
+	return 0;
+}
+early_initcall(omap4_sar_ram_init);
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 07ca05b..4e2da77 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -39,7 +39,6 @@
 static void __iomem *l2cache_base;
 #endif
 
-static void __iomem *sar_ram_base;
 static void __iomem *gic_dist_base_addr;
 
 #ifdef CONFIG_OMAP4_ERRATA_I688
@@ -189,33 +188,6 @@ static int __init omap_l2_cache_init(void)
 early_initcall(omap_l2_cache_init);
 #endif
 
-void __iomem *omap4_get_sar_ram_base(void)
-{
-	return sar_ram_base;
-}
-
-/*
- * SAR RAM used to save and restore the HW
- * context in low power modes
- */
-static int __init omap4_sar_ram_init(void)
-{
-	/*
-	 * To avoid code running on other OMAPs in
-	 * multi-omap builds
-	 */
-	if (!cpu_is_omap44xx())
-		return -ENOMEM;
-
-	/* Static mapping, never released */
-	sar_ram_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K);
-	if (WARN_ON(!sar_ram_base))
-		return -ENOMEM;
-
-	return 0;
-}
-early_initcall(omap4_sar_ram_init);
-
 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h
index fe5b545..e99955f 100644
--- a/arch/arm/mach-omap2/omap4-sar-layout.h
+++ b/arch/arm/mach-omap2/omap4-sar-layout.h
@@ -11,6 +11,32 @@
 #ifndef OMAP_ARCH_OMAP4_SAR_LAYOUT_H
 #define OMAP_ARCH_OMAP4_SAR_LAYOUT_H
 
+#include <mach/hardware.h>
+#include <mach/ctrl_module_pad_core_44xx.h>
+
+#include "cm1_44xx.h"
+#include "cm2_44xx.h"
+#include "prcm-common.h"
+
+/*
+ * The SAR RAM is maintained during Device OFF mode.
+ * It is split into 4 banks with different privilege accesses
+ *
+ * ---------------------------------------------------------------------
+ * Access mode			Bank	Address Range
+ * ---------------------------------------------------------------------
+ * HS/GP : Public		1	0x4A32_6000 - 0x4A32_6FFF (4kB)
+ * HS/GP : Public, Secured
+ * if padconfaccdisable=1	2	0x4A32_7000 - 0x4A32_73FF (1kB)
+ * HS/EMU : Secured
+ * GP : Public			3	0x4A32_8000 - 0x4A32_87FF (2kB)
+ * HS/GP :
+ * Secure Priviledge,
+ * write once.			4	0x4A32_9000 - 0x4A32_93FF (1kB)
+ * ---------------------------------------------------------------------
+ * The SAR RAM save regiter layout is fixed since restore is done by hardware.
+ */
+
 /*
  * SAR BANK offsets from base address OMAP44XX_SAR_RAM_BASE
  */
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 8d7de4f..43cacef 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -124,4 +124,12 @@ static inline int omap4_twl_init(void)
 }
 #endif
 
+#ifdef CONFIG_PM
+extern int omap_sar_save(void);
+#else
+static inline void omap_sar_save(void)
+{
+}
+#endif
+
 #endif
diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h
index c0d478e..8e83e16 100644
--- a/arch/arm/plat-omap/include/plat/omap44xx.h
+++ b/arch/arm/plat-omap/include/plat/omap44xx.h
@@ -22,6 +22,9 @@
 #define L4_PER_44XX_BASE		0x48000000
 #define L4_EMU_44XX_BASE		0x54000000
 #define L3_44XX_BASE			0x44000000
+#define L3_44XX_BASE_CLK1		L3_44XX_BASE
+#define L3_44XX_BASE_CLK2		0x44800000
+#define L3_44XX_BASE_CLK3		0x45000000
 #define OMAP44XX_EMIF1_BASE		0x4c000000
 #define OMAP44XX_EMIF2_BASE		0x4d000000
 #define OMAP44XX_DMM_BASE		0x4e000000
@@ -46,6 +49,7 @@
 #define OMAP44XX_MCPDM_BASE		0x40132000
 #define OMAP44XX_MCPDM_L3_BASE		0x49032000
 #define OMAP44XX_SAR_RAM_BASE		0x4a326000
+#define OMAP44XX_SAR_ROM_BASE		0x4a05e000
 
 #define OMAP44XX_MAILBOX_BASE		(L4_44XX_BASE + 0xF4000)
 #define OMAP44XX_HSUSB_OTG_BASE		(L4_44XX_BASE + 0xAB000)
@@ -58,5 +62,7 @@
 #define OMAP44XX_HSUSB_OHCI_BASE	(L4_44XX_BASE + 0x64800)
 #define OMAP44XX_HSUSB_EHCI_BASE	(L4_44XX_BASE + 0x64C00)
 
+#define OMAP44XX_C2C_BASE		0x5c000000
+
 #endif /* __ASM_ARCH_OMAP44XX_H */
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 12/20] ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (10 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 11/20] ARM: OMAP4: PM: Add SAR backup support towards device OFF Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 13/20] ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode Tero Kristo
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Santosh Shilimkar <santosh.shilimkar@ti.com>

The ROM BUG is when MPU Domain OFF wake up sequence that can compromise
IVA and Tesla execution.

At wakeup from MPU OFF on HS device only (not GP device), when
restoring the Secure RAM, the ROM Code reconfigures the clocks the
same way it is done at Cold Reset.
The IVAHD Clocks and Power Domain settings are:
	IVAHD_CM2 IVAHD_CLKCTRL_MODULE_MODE = DISABLE
	IVAHD_CM2 SL2_CLKCTRL_MODULE_MODE = DISABLE
	IVAHD_CM2 SL2_CLKSTCTRL_CLKTRCTRL = HW_AUTO
	IVAHD_PRM IVAHD_PWRSTCTRL_POWERSTATE = OFF
The TESLA Clocks and Power Domain settings are:
	TESLA_CM1 TESLA_CLKCTRL_MODULE_MODE = DISABLE
	TESLA_CM1 TESLA_CLKSTCTRL_CLKTRCTRL = HW_AUTO
	TESLA_PRM TESLA_PWRSTCTRL_POWERSTATE = OFF

This patch fixes the low power OFF mode code so that the these
registers are saved and restore across MPU OFF state.

Also because of this limitation, MPU OFF alone is not targeted without
device OFF to avoid IVAHD and TESLA execution impact

This erratum impacts only OMAP4430 HS/EMU and is fixed on devices from
OMAP4430 ES2.3 onwards.

Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[t-kristo at ti.com: added omap4 pm errata support]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   52 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.h                  |    1 +
 arch/arm/mach-omap2/pm44xx.c              |   11 ++++++
 3 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index da84339..a361a30 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -52,6 +52,7 @@
 
 #include <plat/omap44xx.h>
 
+#include "iomap.h"
 #include "common.h"
 #include "omap4-sar-layout.h"
 #include "pm.h"
@@ -76,6 +77,24 @@ static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
 static struct powerdomain *mpuss_pd, *core_pd;
 static void __iomem *sar_base;
 
+struct reg_tuple {
+	void __iomem *addr;
+	u32 val;
+};
+
+static struct reg_tuple tesla_reg[] = {
+	{.addr = OMAP4430_CM_TESLA_CLKSTCTRL},
+	{.addr = OMAP4430_CM_TESLA_TESLA_CLKCTRL},
+	{.addr = OMAP4430_PM_TESLA_PWRSTCTRL},
+};
+
+static struct reg_tuple ivahd_reg[] = {
+	{.addr = OMAP4430_CM_IVAHD_CLKSTCTRL},
+	{.addr = OMAP4430_CM_IVAHD_IVAHD_CLKCTRL},
+	{.addr = OMAP4430_CM_IVAHD_SL2_CLKCTRL},
+	{.addr = OMAP4430_PM_IVAHD_PWRSTCTRL}
+};
+
 /*
  * Program the wakeup routine address for the CPU0 and CPU1
  * used for OFF or DORMANT wakeup.
@@ -216,6 +235,34 @@ static void save_l2x0_context(void)
 {}
 #endif
 
+static inline void save_ivahd_tesla_regs(void)
+{
+	int i;
+
+	if (!IS_PM44XX_ERRATUM(PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(tesla_reg); i++)
+		tesla_reg[i].val = __raw_readl(tesla_reg[i].addr);
+
+	for (i = 0; i < ARRAY_SIZE(ivahd_reg); i++)
+		ivahd_reg[i].val = __raw_readl(ivahd_reg[i].addr);
+}
+
+static inline void restore_ivahd_tesla_regs(void)
+{
+	int i;
+
+	if (!IS_PM44XX_ERRATUM(PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(tesla_reg); i++)
+		__raw_writel(tesla_reg[i].val, tesla_reg[i].addr);
+
+	for (i = 0; i < ARRAY_SIZE(ivahd_reg); i++)
+		__raw_writel(ivahd_reg[i].val, ivahd_reg[i].addr);
+}
+
 /**
  * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
  * The purpose of this function is to manage low power programming
@@ -274,9 +321,11 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 			goto sar_save_failed;
 		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	} else if (pwrdm_read_next_func_pwrst(mpuss_pd) ==
 		   PWRDM_FUNC_PWRST_OSWR) {
+		save_ivahd_tesla_regs();
 		save_state = 2;
 	}
 
@@ -301,6 +350,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_FUNC_PWRST_ON);
 
+	if (omap4_mpuss_read_prev_context_state())
+		restore_ivahd_tesla_regs();
+
 	if (pwrdm_read_prev_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF) {
 		omap4_dpll_resume_off();
 		omap4_cm_resume_off();
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 43cacef..a6379a7 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -89,6 +89,7 @@ static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #endif		/* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
 
 #define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_xxx	(1 << 0)
+#define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx	(1 << 1)
 
 #if defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index eb3e073..7e10d4a 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -194,6 +194,17 @@ int __init omap4_pm_init(void)
 
 	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
+	/*
+	 * ROM code initializes IVAHD and TESLA clock registers during
+	 * secure RAM restore phase on omap4430 EMU/HS devices, thus
+	 * IVAHD / TESLA clock registers must be saved / restored
+	 * during MPU OSWR / device off.
+	 */
+	if (omap_rev() >= OMAP4430_REV_ES1_0 &&
+	    omap_rev() < OMAP4430_REV_ES2_3 &&
+	    omap_type() != OMAP2_DEVICE_TYPE_GP)
+		pm44xx_errata |= PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx;
+
 #ifdef CONFIG_SUSPEND
 	omap_pm_suspend = omap4_pm_suspend;
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 13/20] ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (11 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 12/20] ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 14/20] ARM: OMAP4: PM: Mark the PPI and SPI interrupts as non-secure for GP Tero Kristo
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Rajendra Nayak <rnayak@ti.com>

On HS devices on the way out of MPU OSWR and OFF ROM code wrongly
overwrites the CM L3INSTR registers. So to avoid this, save them and
restore on the way out from MPU OSWR/OFF.

This errata applies to all HS/EMU versions of OMAP4.

Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[t-kristo at ti.com: added omap4 pm errata support]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   34 ++++++++++++++++++++++++++++-
 arch/arm/mach-omap2/pm.h                  |    1 +
 arch/arm/mach-omap2/pm44xx.c              |    8 ++++++
 3 files changed, 42 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index a361a30..e09e871 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -95,6 +95,12 @@ static struct reg_tuple ivahd_reg[] = {
 	{.addr = OMAP4430_PM_IVAHD_PWRSTCTRL}
 };
 
+static struct reg_tuple l3instr_reg[] = {
+	{.addr = OMAP4430_CM_L3INSTR_L3_3_CLKCTRL},
+	{.addr = OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL},
+	{.addr = OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL},
+};
+
 /*
  * Program the wakeup routine address for the CPU0 and CPU1
  * used for OFF or DORMANT wakeup.
@@ -263,6 +269,28 @@ static inline void restore_ivahd_tesla_regs(void)
 		__raw_writel(ivahd_reg[i].val, ivahd_reg[i].addr);
 }
 
+static inline void save_l3instr_regs(void)
+{
+	int i;
+
+	if (!IS_PM44XX_ERRATUM(PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(l3instr_reg); i++)
+		l3instr_reg[i].val = __raw_readl(l3instr_reg[i].addr);
+}
+
+static inline void restore_l3instr_regs(void)
+{
+	int i;
+
+	if (!IS_PM44XX_ERRATUM(PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(l3instr_reg); i++)
+		__raw_writel(l3instr_reg[i].val, l3instr_reg[i].addr);
+}
+
 /**
  * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
  * The purpose of this function is to manage low power programming
@@ -322,10 +350,12 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
 		save_ivahd_tesla_regs();
+		save_l3instr_regs();
 		save_state = 3;
 	} else if (pwrdm_read_next_func_pwrst(mpuss_pd) ==
 		   PWRDM_FUNC_PWRST_OSWR) {
 		save_ivahd_tesla_regs();
+		save_l3instr_regs();
 		save_state = 2;
 	}
 
@@ -350,8 +380,10 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_FUNC_PWRST_ON);
 
-	if (omap4_mpuss_read_prev_context_state())
+	if (omap4_mpuss_read_prev_context_state()) {
 		restore_ivahd_tesla_regs();
+		restore_l3instr_regs();
+	}
 
 	if (pwrdm_read_prev_func_pwrst(core_pd) == PWRDM_FUNC_PWRST_OFF) {
 		omap4_dpll_resume_off();
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index a6379a7..dfaec5e 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -90,6 +90,7 @@ static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 
 #define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_xxx	(1 << 0)
 #define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx	(1 << 1)
+#define PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx	(1 << 2)
 
 #if defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 7e10d4a..271b166 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -205,6 +205,14 @@ int __init omap4_pm_init(void)
 	    omap_type() != OMAP2_DEVICE_TYPE_GP)
 		pm44xx_errata |= PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx;
 
+	/*
+	 * Similar to above errata, ROM code modifies L3INSTR clock
+	 * registers also and these must be saved / restored during
+	 * MPU OSWR / device off.
+	 */
+	if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+		pm44xx_errata |= PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx;
+
 #ifdef CONFIG_SUSPEND
 	omap_pm_suspend = omap4_pm_suspend;
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 14/20] ARM: OMAP4: PM: Mark the PPI and SPI interrupts as non-secure for GP
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (12 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 13/20] ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 15/20] ARM: OMAP4430: PM: workaround for DDR corruption on second CS Tero Kristo
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Axel Haslam <axelhaslam@gmail.com>

ROM code restores part of the GIC context during wakeup from device
off mode from the SAR RAM. If the PPI and SPI interrupts are not
marked as non-secure on GP chips, this crashes the device during
wakeup, thus mark them as non-secure.

Signed-off-by: Axel Haslam <axelhaslam@gmail.com>
[t-kristo at ti.com: fixed commit message, merged multiple patches to one]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/common.h           |    1 +
 arch/arm/mach-omap2/omap-wakeupgen.c   |   22 ++++++++++++++++++++++
 arch/arm/mach-omap2/omap4-common.c     |    8 ++++++++
 arch/arm/mach-omap2/omap4-sar-layout.h |    3 +++
 4 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index a793ab3..22addd0 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -247,6 +247,7 @@ static inline void __iomem *omap4_get_scu_base(void)
 
 extern void __init gic_init_irq(void);
 extern void gic_dist_disable(void);
+extern u32 gic_readl(u32 offset, u8 idx);
 extern void omap_smc1(u32 fn, u32 arg);
 extern void __iomem *omap4_get_sar_ram_base(void);
 extern void omap_do_wfi(void);
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 1cffb3a..da144ae 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -39,6 +39,7 @@
 #define CPU_ENA_OFFSET		0x400
 #define CPU0_ID			0x0
 #define CPU1_ID			0x1
+#define GIC_ISR_NON_SECURE	0xffffffff
 
 static void __iomem *wakeupgen_base;
 static void __iomem *sar_base;
@@ -337,6 +338,7 @@ int __init omap_wakeupgen_init(void)
 {
 	int i;
 	unsigned int boot_cpu = smp_processor_id();
+	int max_spi_reg;
 
 	/* Not supported on OMAP4 ES1.0 silicon */
 	if (omap_rev() == OMAP4430_REV_ES1_0) {
@@ -372,6 +374,26 @@ int __init omap_wakeupgen_init(void)
 	for (i = 0; i < NR_IRQS; i++)
 		irq_target_cpu[i] = boot_cpu;
 
+	/*
+	 * Find out how many interrupts are supported.
+	 * OMAP4 supports max of 128 SPIs where as GIC can support
+	 * up to 1020 interrupt sources. On OMAP4, maximum SPIs are
+	 * fused in DIST_CTR bit-fields as 128. Hence the code is safe
+	 * from reserved register writes since its well within 1020.
+	 */
+	max_spi_reg = gic_readl(GIC_DIST_CTR, 0) & 0x1f;
+
+	if (omap_type() == OMAP2_DEVICE_TYPE_GP) {
+		sar_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K);
+		sar_writel(GIC_ISR_NON_SECURE, SAR_ICDISR_CPU0_OFFSET, 0);
+		sar_writel(GIC_ISR_NON_SECURE, SAR_ICDISR_CPU1_OFFSET, 0);
+		for (i = 0; i < max_spi_reg; i++)
+			sar_writel(GIC_ISR_NON_SECURE, SAR_ICDISR_SPI_OFFSET,
+				   i);
+		iounmap(sar_base);
+		sar_base = NULL;
+	}
+
 	irq_hotplug_init();
 	irq_pm_init();
 
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 4e2da77..33decee 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -114,6 +114,14 @@ void gic_dist_disable(void)
 		__raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
 }
 
+u32 gic_readl(u32 offset, u8 idx)
+{
+	if (!gic_dist_base_addr)
+		return 0;
+
+	return __raw_readl(gic_dist_base_addr + offset + 4 * idx);
+}
+
 #ifdef CONFIG_CACHE_L2X0
 
 void __iomem *omap4_get_l2cache_base(void)
diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h
index e99955f..57c44fa 100644
--- a/arch/arm/mach-omap2/omap4-sar-layout.h
+++ b/arch/arm/mach-omap2/omap4-sar-layout.h
@@ -61,6 +61,9 @@
 #define SAR_BACKUP_STATUS_OFFSET		(SAR_BANK3_OFFSET + 0x500)
 #define SAR_SECURE_RAM_SIZE_OFFSET		(SAR_BANK3_OFFSET + 0x504)
 #define SAR_SECRAM_SAVED_AT_OFFSET		(SAR_BANK3_OFFSET + 0x508)
+#define SAR_ICDISR_CPU0_OFFSET			(SAR_BANK3_OFFSET + 0x50c)
+#define SAR_ICDISR_CPU1_OFFSET			(SAR_BANK3_OFFSET + 0x510)
+#define SAR_ICDISR_SPI_OFFSET			(SAR_BANK3_OFFSET + 0x514)
 
 /* WakeUpGen save restore offset from OMAP44XX_SAR_RAM_BASE */
 #define WAKEUPGENENB_OFFSET_CPU0		(SAR_BANK3_OFFSET + 0x684)
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 15/20] ARM: OMAP4430: PM: workaround for DDR corruption on second CS
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (13 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 14/20] ARM: OMAP4: PM: Mark the PPI and SPI interrupts as non-secure for GP Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 16/20] TEMP: ARM: OMAP4: prevent voltage transitions Tero Kristo
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Santosh Shilimkar <santosh.shilimkar@ti.com>

Work around for Errata ID: i632 "LPDDR2 Corruption After OFF Mode
Transition When CS1 Is Used On EMIF" which impacts OMAP443x silicon
The issue occurs when EMIF_SDRAM_CONFIG is restored first before
EMIF_SDRAM_CONFIG_2 is not yet restored, the register configuration
is not set properly, we apply the required workaround allowing
the restore sequence to work properly.

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 .../include/mach/ctrl_module_wkup_44xx.h           |    2 +
 arch/arm/mach-omap2/pm44xx.c                       |   37 ++++++++++++++++++++
 2 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h b/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
index a0af9ba..b763a79 100644
--- a/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
+++ b/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
@@ -28,6 +28,8 @@
 #define OMAP4_CTRL_MODULE_WKUP_IP_REVISION		0x0000
 #define OMAP4_CTRL_MODULE_WKUP_IP_HWINFO		0x0004
 #define OMAP4_CTRL_MODULE_WKUP_IP_SYSCONFIG		0x0010
+#define OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG	0x0114
+#define OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG	0x011c
 #define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_0	0x0460
 #define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_1	0x0464
 #define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_2	0x0468
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 271b166..8b2cc21 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -17,12 +17,18 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <asm/system_misc.h>
+#include <linux/io.h>
+
+#include <mach/ctrl_module_wkup_44xx.h>
+#include <mach/hardware.h>
 
 #include "common.h"
 #include "clockdomain.h"
 #include "powerdomain.h"
 #include "pm.h"
 
+#define EMIF_SDRAM_CONFIG2_OFFSET	0xc
+
 struct power_state {
 	struct powerdomain *pwrdm;
 	u32 next_state;
@@ -146,6 +152,37 @@ int __init omap4_pm_init(void)
 
 	pr_err("Power Management for TI OMAP4.\n");
 
+	/*
+	 * Work around for OMAP443x Errata i632: "LPDDR2 Corruption After OFF
+	 * Mode Transition When CS1 Is Used On EMIF":
+	 * Overwrite EMIF1/EMIF2
+	 * SECURE_EMIF1_SDRAM_CONFIG2_REG
+	 * SECURE_EMIF2_SDRAM_CONFIG2_REG
+	 */
+	if (cpu_is_omap443x()) {
+		void __iomem *secure_ctrl_mod;
+		void __iomem *emif1;
+		void __iomem *emif2;
+		u32 val;
+
+		secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+		emif1 = ioremap(OMAP44XX_EMIF1_BASE, SZ_1M);
+		emif2 = ioremap(OMAP44XX_EMIF2_BASE, SZ_1M);
+
+		BUG_ON(!secure_ctrl_mod || !emif1 || !emif2);
+
+		val = __raw_readl(emif1 + EMIF_SDRAM_CONFIG2_OFFSET);
+		__raw_writel(val, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
+		val = __raw_readl(emif2 + EMIF_SDRAM_CONFIG2_OFFSET);
+		__raw_writel(val, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);
+		wmb();
+		iounmap(secure_ctrl_mod);
+		iounmap(emif1);
+		iounmap(emif2);
+	}
+
 	ret = pwrdm_for_each(pwrdms_setup, NULL);
 	if (ret) {
 		pr_err("Failed to setup powerdomains\n");
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 16/20] TEMP: ARM: OMAP4: prevent voltage transitions
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (14 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 15/20] ARM: OMAP4430: PM: workaround for DDR corruption on second CS Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 17/20] ARM: OMAP4: put cpu1 back to sleep if no wake request Tero Kristo
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

During device off, the off-mode voltage transitions are enabled on reset.
Because the voltage control logic is not still completely functional for
OMAP4, we must disable the voltage transitions for device off for now.
This can only be done by disabling the I2C channel it seems.

This patch does not prevent voltage scaling done by voltdm->scale / DVFS.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm44xx.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 8b2cc21..341655e 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -26,6 +26,9 @@
 #include "clockdomain.h"
 #include "powerdomain.h"
 #include "pm.h"
+#include "voltage.h"
+#include "prm44xx.h"
+#include "prm-regbits-44xx.h"
 
 #define EMIF_SDRAM_CONFIG2_OFFSET	0xc
 
@@ -144,6 +147,7 @@ int __init omap4_pm_init(void)
 	int ret;
 	struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm, *l4wkup;
 	struct clockdomain *ducati_clkdm, *l3_2_clkdm, *l4_per_clkdm;
+	struct voltagedomain *mpu_voltdm;
 
 	if (omap_rev() == OMAP4430_REV_ES1_0) {
 		WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
@@ -223,6 +227,24 @@ int __init omap4_pm_init(void)
 		goto err2;
 	}
 
+	/*
+	 * XXX: voltage config is not still completely valid for
+	 * OMAP4, and this causes crashes on some platform during
+	 * device off because voltage transitions for device off
+	 * are enabled on reset. Thus, we have to disable the I2C
+	 * channel completely in the VOLTCTRL register to avoid
+	 * trouble. Remove this once voltconfigs are valid.
+	 */
+	mpu_voltdm = voltdm_lookup("mpu");
+	if (!mpu_voltdm) {
+		pr_err("Failed to get MPU voltdm\n");
+		goto err2;
+	}
+	mpu_voltdm->write(OMAP4430_VDD_MPU_I2C_DISABLE_MASK |
+			  OMAP4430_VDD_CORE_I2C_DISABLE_MASK |
+			  OMAP4430_VDD_IVA_I2C_DISABLE_MASK,
+			  OMAP4_PRM_VOLTCTRL_OFFSET);
+
 	ret = omap4_mpuss_init();
 	if (ret) {
 		pr_err("Failed to initialise OMAP4 MPUSS\n");
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 17/20] ARM: OMAP4: put cpu1 back to sleep if no wake request
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (15 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 16/20] TEMP: ARM: OMAP4: prevent voltage transitions Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 18/20] ARM: OMAP4460: wakeupgen: set GIC_CPU0 backup status flag always Tero Kristo
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

If AUX_CORE_BOOT0 does not indicate wakeup request for cpu1, put it back
to off. This is needed during wakeup from device off to prevent cpu1
from being stuck indefinitely in the wakeup loop and also to prevent
wakeup problem on GP chips with device off mode.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-headsmp.S |   83 ++++++++++++++++++++++++++++++++++--
 1 files changed, 79 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
index 7bbb66e..de76666 100644
--- a/arch/arm/mach-omap2/omap-headsmp.S
+++ b/arch/arm/mach-omap2/omap-headsmp.S
@@ -19,8 +19,75 @@
 #include <linux/init.h>
 
 #include <plat/omap44xx.h>
+#include <mach/omap-secure.h>
+#include <asm/smp_scu.h>
+
+#include "prcm_mpu44xx.h"
+
+#define CPU1_PWRSTCTRL (OMAP4430_PRCM_MPU_BASE + OMAP4430_PRCM_MPU_CPU1_INST + \
+			OMAP4_PM_CPU1_PWRSTCTRL_OFFSET)
 
 	__CPUINIT
+
+/*
+ * Put CPU1 to off mode.
+ * Programs CPU1_PWRSTCTRL to OFF via secure API, and enters WFI which
+ * triggers the HW transition. omap_do_wfi() can't be used as we don't
+ * have MMU enabled and neither do we have stack at this point.
+ */
+ENTRY(omap_cpu1_off)
+	/*
+	 * If we are running from a cold boot, we can't enter idle
+	 * yet as PRCM does not contain valid programming for it.
+	 * Thus, we check the CPU1_PWRSTCTRL and see whether it contains
+	 * reset value (POWERSTATE=2), and if this is the case, exit early
+	 */
+	ldr	r12, =CPU1_PWRSTCTRL
+	ldr	r0, [r12]
+	and	r0, #3
+	cmp	r0, #2
+	beq	exit_cpu1_off		@ can't idle yet, exit
+
+	/*
+	 * Program SCU power state for this CPU to POWEROFF. Secure API
+	 * is used for this.
+	 */
+	mov	r0, #SCU_PM_POWEROFF
+	mov	r1, #0x0
+	ldr	r12, =OMAP4_MON_SCU_PWR_INDEX
+	dsb
+	smc     #0
+	dsb
+
+	isb
+	dsb
+	dmb
+	/*
+	 * Execute a WFI instruction to enter OFF.
+	 * Sixteen NOPs added after WFI to prevent speculative
+	 * pipeline execution.
+	 */
+	wfi
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+exit_cpu1_off:
+	mov	pc, lr
+ENDPROC(omap_cpu1_off)
+
 /*
  * OMAP4 specific entry point for secondary CPU to jump from ROM
  * code.  This routine also provides a holding flag into which
@@ -29,32 +96,40 @@
  * register AuxCoreBoot0.
  */
 ENTRY(omap_secondary_startup)
-hold:	ldr	r12,=0x103
+	ldr	r12,=0x103
 	dsb
 	smc	#0			@ read from AuxCoreBoot0
 	mov	r0, r0, lsr #9
 	mrc	p15, 0, r4, c0, c0, 5
 	and	r4, r4, #0x0f
 	cmp	r0, r4
-	bne	hold
+	beq	omap_cont_boot
+
+	bl	omap_cpu1_off
+	b	omap_secondary_startup
 
 	/*
 	 * we've been released from the wait loop,secondary_stack
 	 * should now contain the SVC stack for this core
 	 */
+omap_cont_boot:
 	b	secondary_startup
 ENDPROC(omap_secondary_startup)
 
 ENTRY(omap_secondary_startup_4460)
-hold_2:	ldr	r12,=0x103
+	ldr	r12,=0x103
 	dsb
 	smc	#0			@ read from AuxCoreBoot0
 	mov	r0, r0, lsr #9
 	mrc	p15, 0, r4, c0, c0, 5
 	and	r4, r4, #0x0f
 	cmp	r0, r4
-	bne	hold_2
+	beq	omap4460_cont_boot
+
+	bl	omap_cpu1_off
+	b	omap_secondary_startup_4460
 
+omap4460_cont_boot:
 	/*
 	 * GIC distributor control register has changed between
 	 * CortexA9 r1pX and r2pX. The Control Register secure
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 18/20] ARM: OMAP4460: wakeupgen: set GIC_CPU0 backup status flag always
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (16 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 17/20] ARM: OMAP4: put cpu1 back to sleep if no wake request Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:31 ` [PATCHv3 19/20] ARM: OMAP4: PM: enable off mode by default Tero Kristo
  2012-06-12 15:41 ` [PATCHv3 20/20] ARM: OMAP4430: PM: errata i625, WUGEN lost for GP devices after OFF mode Tero Kristo
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

Without this, CPU0 will crash in the ROM code during wakeup from
device off. This patch also clears the GIC save area, to prevent
ROM code from writing garbage to the GIC registers during wakeup.
The actual GIC restore is done by kernel.

This bug fix applies only to OMAP4460, it is fixed on OMAP4470.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/omap-wakeupgen.c   |   22 ++++++++++++++++++++++
 arch/arm/mach-omap2/omap4-sar-layout.h |    1 +
 arch/arm/mach-omap2/pm.h               |    1 +
 3 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index da144ae..59620a4 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -31,6 +31,7 @@
 
 #include "omap4-sar-layout.h"
 #include "common.h"
+#include "pm.h"
 
 #define NR_REG_BANKS		4
 #define MAX_IRQS		128
@@ -383,13 +384,34 @@ int __init omap_wakeupgen_init(void)
 	 */
 	max_spi_reg = gic_readl(GIC_DIST_CTR, 0) & 0x1f;
 
+	/*
+	 * Set CPU0 GIC backup flag permanently for omap4460 GP,
+	 * this is needed because of the ROM code bug that breaks
+	 * GIC during wakeup from device off. This errata fix also
+	 * clears the GIC save area during init to prevent restoring
+	 * garbage to the GIC.
+	 */
+	if (cpu_is_omap446x() && omap_type() == OMAP2_DEVICE_TYPE_GP)
+		pm44xx_errata |= PM_OMAP4_ROM_CPU1_BACKUP_ERRATUM_xxx;
+
 	if (omap_type() == OMAP2_DEVICE_TYPE_GP) {
 		sar_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K);
+
+		if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_CPU1_BACKUP_ERRATUM_xxx))
+			for (i = SAR_BACKUP_STATUS_OFFSET;
+			     i < WAKEUPGENENB_OFFSET_CPU0; i += 4)
+				sar_writel(0, i, 0);
+
 		sar_writel(GIC_ISR_NON_SECURE, SAR_ICDISR_CPU0_OFFSET, 0);
 		sar_writel(GIC_ISR_NON_SECURE, SAR_ICDISR_CPU1_OFFSET, 0);
 		for (i = 0; i < max_spi_reg; i++)
 			sar_writel(GIC_ISR_NON_SECURE, SAR_ICDISR_SPI_OFFSET,
 				   i);
+
+		if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_CPU1_BACKUP_ERRATUM_xxx))
+			__raw_writel(SAR_BACKUP_STATUS_GIC_CPU0,
+				     sar_base + SAR_BACKUP_STATUS_OFFSET);
+
 		iounmap(sar_base);
 		sar_base = NULL;
 	}
diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h
index 57c44fa..b4adfbe 100644
--- a/arch/arm/mach-omap2/omap4-sar-layout.h
+++ b/arch/arm/mach-omap2/omap4-sar-layout.h
@@ -64,6 +64,7 @@
 #define SAR_ICDISR_CPU0_OFFSET			(SAR_BANK3_OFFSET + 0x50c)
 #define SAR_ICDISR_CPU1_OFFSET			(SAR_BANK3_OFFSET + 0x510)
 #define SAR_ICDISR_SPI_OFFSET			(SAR_BANK3_OFFSET + 0x514)
+#define SAR_BACKUP_STATUS_GIC_CPU0		0x1
 
 /* WakeUpGen save restore offset from OMAP44XX_SAR_RAM_BASE */
 #define WAKEUPGENENB_OFFSET_CPU0		(SAR_BANK3_OFFSET + 0x684)
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index dfaec5e..63af57e 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -91,6 +91,7 @@ static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #define PM_OMAP4_ROM_SMP_BOOT_ERRATUM_xxx	(1 << 0)
 #define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx	(1 << 1)
 #define PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx	(1 << 2)
+#define PM_OMAP4_ROM_CPU1_BACKUP_ERRATUM_xxx	(1 << 3)
 
 #if defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 19/20] ARM: OMAP4: PM: enable off mode by default
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (17 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 18/20] ARM: OMAP4460: wakeupgen: set GIC_CPU0 backup status flag always Tero Kristo
@ 2012-06-12 15:31 ` Tero Kristo
  2012-06-12 15:41 ` [PATCHv3 20/20] ARM: OMAP4430: PM: errata i625, WUGEN lost for GP devices after OFF mode Tero Kristo
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:31 UTC (permalink / raw)
  To: linux-arm-kernel

System will now enter device off by default during suspend.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm44xx.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 341655e..8054afc 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -114,7 +114,11 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	pwrst->pwrdm = pwrdm;
 	pwrst->next_state = pwrdm_get_achievable_func_pwrst(
 						pwrdm,
-						PWRDM_FUNC_PWRST_OSWR);
+						PWRDM_FUNC_PWRST_OFF);
+
+	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE)
+		pwrst->next_state = PWRDM_FUNC_PWRST_OFF;
+
 	list_add(&pwrst->node, &pwrst_list);
 
 	return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 20/20] ARM: OMAP4430: PM: errata i625, WUGEN lost for GP devices after OFF mode
  2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
                   ` (18 preceding siblings ...)
  2012-06-12 15:31 ` [PATCHv3 19/20] ARM: OMAP4: PM: enable off mode by default Tero Kristo
@ 2012-06-12 15:41 ` Tero Kristo
  19 siblings, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-12 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implements errata i625.

When coming back from device off mode, the Cortex-A9 WUGEN enable registers
are not restored by ROM code. The work around disables device power OFF
to maintain the proper register settings.
The affected devices are OMAP4430GP ES2.0 to ES2.2.

Based on work done by Mykola Oleksiienko and Konstantin Shlyakhovoy.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
 arch/arm/mach-omap2/pm.h     |    1 +
 arch/arm/mach-omap2/pm44xx.c |   12 +++++++++++-
 2 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 63af57e..f85ef2d 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -92,6 +92,7 @@ static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM_xxx	(1 << 1)
 #define PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx	(1 << 2)
 #define PM_OMAP4_ROM_CPU1_BACKUP_ERRATUM_xxx	(1 << 3)
+#define PM_OMAP4_ROM_WUGEN_LOST_ERRATUM_i625	(1 << 4)
 
 #if defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 8054afc..c1dc0d9 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -116,7 +116,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 						pwrdm,
 						PWRDM_FUNC_PWRST_OFF);
 
-	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE)
+	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE &&
+	    !IS_PM44XX_ERRATUM(PM_OMAP4_ROM_WUGEN_LOST_ERRATUM_i625))
 		pwrst->next_state = PWRDM_FUNC_PWRST_OFF;
 
 	list_add(&pwrst->node, &pwrst_list);
@@ -276,6 +277,15 @@ int __init omap4_pm_init(void)
 	if (omap_type() != OMAP2_DEVICE_TYPE_GP)
 		pm44xx_errata |= PM_OMAP4_ROM_L3INSTR_ERRATUM_xxx;
 
+	/*
+	 * The OFF mode isn't fully supported for OMAP4430GP ES2.0 - ES2.2
+	 * due to errata i625
+	 * On ES1.0 OFF mode is not supported due to errata i498
+	 */
+	if (cpu_is_omap443x() && omap_type() == OMAP2_DEVICE_TYPE_GP &&
+	    omap_rev() < OMAP4430_REV_ES2_3)
+		pm44xx_errata |= PM_OMAP4_ROM_WUGEN_LOST_ERRATUM_i625;
+
 #ifdef CONFIG_SUSPEND
 	omap_pm_suspend = omap4_pm_suspend;
 #endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCHv3 03/20] ARM: OMAP4: PM: add support for device off
  2012-06-12 15:31 ` [PATCHv3 03/20] ARM: OMAP4: PM: add support for " Tero Kristo
@ 2012-06-13 15:21   ` Jean Pihet
  2012-06-14  9:18     ` Tero Kristo
  2012-06-14 13:53     ` Tero Kristo
  0 siblings, 2 replies; 24+ messages in thread
From: Jean Pihet @ 2012-06-13 15:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Tero,

I have a few remarks regarding the genericity of this code. I think it
is better if the code in powerdomain.c stays generic and that the
platform specific checks and operations be moved in the specific
functions (via the pwrdm_ops struct).

On Tue, Jun 12, 2012 at 5:31 PM, Tero Kristo <t-kristo@ti.com> wrote:
> On OMAP4+, device wide off-mode has its own enable mechanism in addition
> to powerdomain target states. This patch adds support for this on top
> of functional power states by overloading the OFF state for core pwrdm.
> On pwrdm level, the deepest power state supported by core pwrdm is OSWR.
> When user (e.g. suspend) programs core pwrdm target as OFF, the functional
> power state for the domain will be OSWR with the additional device off
> enabled. Previous power state information will reflect this also.
>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> ---
> ?arch/arm/mach-omap2/powerdomain.c ? ? ? ? ? | ? 17 +++++++++
> ?arch/arm/mach-omap2/powerdomain.h ? ? ? ? ? | ? 13 +++++++-
> ?arch/arm/mach-omap2/powerdomain44xx.c ? ? ? | ? 48 +++++++++++++++++++++++++++
> ?arch/arm/mach-omap2/powerdomains44xx_data.c | ? ?3 +-
> ?4 files changed, 79 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> index ac63f86..78a9308 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -677,6 +677,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
> ? ? ? ?int sleep_switch = -1, ret = 0, hwsup = 0;
> ? ? ? ?int new_func_pwrst, next_func_pwrst, pwrst, logic;
> ? ? ? ?u8 curr_pwrst;
> + ? ? ? bool extra_off_enable = false;
> + ? ? ? bool has_extra_off = false;
>
> ? ? ? ?if (!pwrdm || IS_ERR(pwrdm)) {
> ? ? ? ? ? ? ? ?pr_debug("%s: invalid params: pwrdm=%p\n", __func__, pwrdm);
> @@ -687,6 +689,13 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
>
> ? ? ? ?mutex_lock(&pwrdm->lock);
>
> + ? ? ? /* Check if powerdomain has extra off mode handling */
> + ? ? ? if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE) {
> + ? ? ? ? ? ? ? has_extra_off = true;
> + ? ? ? ? ? ? ? if (func_pwrst == PWRDM_FUNC_PWRST_OFF)
> + ? ? ? ? ? ? ? ? ? ? ? extra_off_enable = true;
> + ? ? ? }
Could those checks be moved in the OMAP4 specific functions, so that
the power domain code stays generic?

> +
> ? ? ? ?new_func_pwrst = pwrdm_get_achievable_func_pwrst(pwrdm, func_pwrst);
> ? ? ? ?pwrst = pwrdm_func_to_pwrst(pwrdm, new_func_pwrst);
> ? ? ? ?logic = pwrdm_func_to_logic_pwrst(pwrdm, new_func_pwrst);
> @@ -741,6 +750,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
>
> + ? ? ? if (has_extra_off && arch_pwrdm->pwrdm_enable_off)
> + ? ? ? ? ? ? ? arch_pwrdm->pwrdm_enable_off(pwrdm, extra_off_enable);
> +
> ?out:
> ? ? ? ?mutex_unlock(&pwrdm->lock);
> ? ? ? ?return ret;
> @@ -810,6 +822,11 @@ int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)
> ? ? ? ?int next_pwrst = pwrdm_read_next_pwrst(pwrdm);
> ? ? ? ?int next_logic = pwrdm_read_logic_retst(pwrdm);
>
> + ? ? ? if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE &&
> + ? ? ? ? ? arch_pwrdm->pwrdm_read_next_off &&
> + ? ? ? ? ? arch_pwrdm->pwrdm_read_next_off(pwrdm))
> + ? ? ? ? ? ? ? return PWRDM_FUNC_PWRST_OFF;
> +
Same comment here. The OMAP4 specific function for
pwrdm_read_next_pwrst could return PWRDM_FUNC_PWRST_OFF.

> ? ? ? ?return pwrdm_pwrst_to_func(pwrdm, next_pwrst, next_logic);
> ?}
>
> diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
> index 0729d91..cc30b94 100644
> --- a/arch/arm/mach-omap2/powerdomain.h
> +++ b/arch/arm/mach-omap2/powerdomain.h
> @@ -75,6 +75,13 @@
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* state without waking up the
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* powerdomain
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
> +/*
> + * OMAP4+ has device off feature, which must be enabled separately in
> + * addition to power domain next state setup. This feature is overloaded
> + * as EXTRA_OFF_ENABLE for core_pwrdm, and is implemented on top of
> + * functional power state
> + */
> +#define PWRDM_HAS_EXTRA_OFF_ENABLE ? ? (1 << 3)
>
> ?/*
> ?* Number of memory banks that are power-controllable. On OMAP4430, the
> @@ -173,7 +180,9 @@ struct powerdomain {
> ?* @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd
> ?* @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep
> ?* @pwrdm_wait_transition: Wait for a pd state transition to complete
> - * @pwrdm_lost_context_rff: Check if pd has lost RFF context (entered off)
> + * @pwrdm_lost_context_rff: Check if pd has lost RFF context (omap4+ device off)
> + * @pwrdm_enable_off: Extra off mode enable for pd (omap4+ device off)
> + * @pwrdm_read_next_off: Check if pd next state is off (omap4+ device off)
> ?*/
> ?struct pwrdm_ops {
> ? ? ? ?int ? ? (*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);
> @@ -199,6 +208,8 @@ struct pwrdm_ops {
> ? ? ? ?int ? ? (*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
> ? ? ? ?int ? ? (*pwrdm_wait_transition)(struct powerdomain *pwrdm);
> ? ? ? ?bool ? ?(*pwrdm_lost_context_rff)(struct powerdomain *pwrdm);
> + ? ? ? void ? ?(*pwrdm_enable_off)(struct powerdomain *pwrdm, bool enable);
> + ? ? ? bool ? ?(*pwrdm_read_next_off)(struct powerdomain *pwrdm);
> ?};
>
> ?int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
> diff --git a/arch/arm/mach-omap2/powerdomain44xx.c b/arch/arm/mach-omap2/powerdomain44xx.c
> index 562f78a..b2bdc0f 100644
> --- a/arch/arm/mach-omap2/powerdomain44xx.c
> +++ b/arch/arm/mach-omap2/powerdomain44xx.c
> @@ -358,6 +358,52 @@ bool omap4_pwrdm_lost_context_rff(struct powerdomain *pwrdm)
> ? ? ? ?return false;
> ?}
>
> +/**
> + * omap4_device_set_next_state_off - setup device off state
> + * @pwrdm: struct powerdomain * to target powerdomain
> + * @enable: true if off-mode should be enabled
> + *
> + * When Device OFF is enabled, Device is allowed to perform
> + * transition to off mode as soon as all power domains in MPU, IVA
> + * and CORE voltage are in OFF or OSWR state (open switch retention)
> + */
> +void omap4_device_set_next_state_off(struct powerdomain *pwrdm, bool enable)
> +{
> + ? ? ? u8 val = enable ? 0x1 : 0x0;
> +
> + ? ? ? if (!(pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE))
> + ? ? ? ? ? ? ? return;
> +
> + ? ? ? omap4_prminst_write_inst_reg(val << OMAP4430_DEVICE_OFF_ENABLE_SHIFT,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP4430_PRM_PARTITION,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP4430_PRM_DEVICE_INST,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET);
> +}
> +
> +
> +/**
> + * omap4_device_read_next_state_off - read device off state
> + * @pwrdm: struct powerdomain * to target powerdomain
> + *
> + * Checks if device off is enabled or not.
> + * Returns true if enabled, false otherwise.
> + */
> +bool omap4_device_read_next_state_off(struct powerdomain *pwrdm)
> +{
> + ? ? ? u32 val;
> +
> + ? ? ? if (!(pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE))
> + ? ? ? ? ? ? ? return false;
> +
> + ? ? ? val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP4430_PRM_DEVICE_INST,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET);
> +
> + ? ? ? val &= OMAP4430_DEVICE_OFF_ENABLE_MASK;
> +
> + ? ? ? return val ? true : false;
> +}
> +
> ?struct pwrdm_ops omap4_pwrdm_operations = {
> ? ? ? ?.pwrdm_func_to_pwrst ? ?= omap2_pwrdm_func_to_pwrst,
> ? ? ? ?.pwrdm_func_to_logic_pwrst ? ? ?= omap2_pwrdm_func_to_logic_pwrst,
> @@ -381,4 +427,6 @@ struct pwrdm_ops omap4_pwrdm_operations = {
> ? ? ? ?.pwrdm_enable_hdwr_sar ?= omap4_pwrdm_enable_hdwr_sar,
> ? ? ? ?.pwrdm_disable_hdwr_sar = omap4_pwrdm_disable_hdwr_sar,
> ? ? ? ?.pwrdm_lost_context_rff = omap4_pwrdm_lost_context_rff,
> + ? ? ? .pwrdm_enable_off ? ? ? = omap4_device_set_next_state_off,
> + ? ? ? .pwrdm_read_next_off ? ?= omap4_device_read_next_state_off,
> ?};
> diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
> index c4de02f..13db876 100644
> --- a/arch/arm/mach-omap2/powerdomains44xx_data.c
> +++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
> @@ -54,7 +54,8 @@ static struct powerdomain core_44xx_pwrdm = {
> ? ? ? ? ? ? ? ?[3] = PWRSTS_ON, ? ? ? ?/* ducati_l2ram */
> ? ? ? ? ? ? ? ?[4] = PWRSTS_ON, ? ? ? ?/* ducati_unicache */
> ? ? ? ?},
> - ? ? ? .flags ? ? ? ? ? ?= PWRDM_HAS_LOWPOWERSTATECHANGE,
> + ? ? ? .flags ? ? ? ? ? ?= PWRDM_HAS_LOWPOWERSTATECHANGE |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? PWRDM_HAS_EXTRA_OFF_ENABLE,
> ?};
>
> ?/* gfx_44xx_pwrdm: 3D accelerator power domain */

Regards,
Jean

> --
> 1.7.4.1
>
> --
> 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

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCHv3 03/20] ARM: OMAP4: PM: add support for device off
  2012-06-13 15:21   ` Jean Pihet
@ 2012-06-14  9:18     ` Tero Kristo
  2012-06-14 13:53     ` Tero Kristo
  1 sibling, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-14  9:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2012-06-13 at 17:21 +0200, Jean Pihet wrote:
> Hi Tero,
> 
> I have a few remarks regarding the genericity of this code. I think it
> is better if the code in powerdomain.c stays generic and that the
> platform specific checks and operations be moved in the specific
> functions (via the pwrdm_ops struct).

Well, I was thinking about this, however it looks like I need to copy
over most of the implementation of omap_set_pwrdm_state and
get_next_achievable_state if I want to do that, or alternatively
overload the underlying omap4 pwrdm code which does not seem that good
solution either.

> 
> On Tue, Jun 12, 2012 at 5:31 PM, Tero Kristo <t-kristo@ti.com> wrote:
> > On OMAP4+, device wide off-mode has its own enable mechanism in addition
> > to powerdomain target states. This patch adds support for this on top
> > of functional power states by overloading the OFF state for core pwrdm.
> > On pwrdm level, the deepest power state supported by core pwrdm is OSWR.
> > When user (e.g. suspend) programs core pwrdm target as OFF, the functional
> > power state for the domain will be OSWR with the additional device off
> > enabled. Previous power state information will reflect this also.
> >
> > Signed-off-by: Tero Kristo <t-kristo@ti.com>
> > ---
> >  arch/arm/mach-omap2/powerdomain.c           |   17 +++++++++
> >  arch/arm/mach-omap2/powerdomain.h           |   13 +++++++-
> >  arch/arm/mach-omap2/powerdomain44xx.c       |   48 +++++++++++++++++++++++++++
> >  arch/arm/mach-omap2/powerdomains44xx_data.c |    3 +-
> >  4 files changed, 79 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> > index ac63f86..78a9308 100644
> > --- a/arch/arm/mach-omap2/powerdomain.c
> > +++ b/arch/arm/mach-omap2/powerdomain.c
> > @@ -677,6 +677,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
> >        int sleep_switch = -1, ret = 0, hwsup = 0;
> >        int new_func_pwrst, next_func_pwrst, pwrst, logic;
> >        u8 curr_pwrst;
> > +       bool extra_off_enable = false;
> > +       bool has_extra_off = false;
> >
> >        if (!pwrdm || IS_ERR(pwrdm)) {
> >                pr_debug("%s: invalid params: pwrdm=%p\n", __func__, pwrdm);
> > @@ -687,6 +689,13 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
> >
> >        mutex_lock(&pwrdm->lock);
> >
> > +       /* Check if powerdomain has extra off mode handling */
> > +       if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE) {
> > +               has_extra_off = true;
> > +               if (func_pwrst == PWRDM_FUNC_PWRST_OFF)
> > +                       extra_off_enable = true;
> > +       }
> Could those checks be moved in the OMAP4 specific functions, so that
> the power domain code stays generic?

I'll try to do that and see what happens. The problem I tried to tackle
with this implementation is that even when core next state is programmed
to func OFF, we must program the powerdomain itself to OSWR, which the
current functional pwrst framework does not support too well.... or as
you say, I need to re-write the omap4 pwrdm state handling code itself
which kind of eats the benefit of the functional power states away.

> 
> > +
> >        new_func_pwrst = pwrdm_get_achievable_func_pwrst(pwrdm, func_pwrst);
> >        pwrst = pwrdm_func_to_pwrst(pwrdm, new_func_pwrst);
> >        logic = pwrdm_func_to_logic_pwrst(pwrdm, new_func_pwrst);
> > @@ -741,6 +750,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
> >                break;
> >        }
> >
> > +       if (has_extra_off && arch_pwrdm->pwrdm_enable_off)
> > +               arch_pwrdm->pwrdm_enable_off(pwrdm, extra_off_enable);
> > +
> >  out:
> >        mutex_unlock(&pwrdm->lock);
> >        return ret;
> > @@ -810,6 +822,11 @@ int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)
> >        int next_pwrst = pwrdm_read_next_pwrst(pwrdm);
> >        int next_logic = pwrdm_read_logic_retst(pwrdm);
> >
> > +       if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE &&
> > +           arch_pwrdm->pwrdm_read_next_off &&
> > +           arch_pwrdm->pwrdm_read_next_off(pwrdm))
> > +               return PWRDM_FUNC_PWRST_OFF;
> > +
> Same comment here. The OMAP4 specific function for
> pwrdm_read_next_pwrst could return PWRDM_FUNC_PWRST_OFF.

Same issue.

Anyway, I'll try to fiddle with the code bit more and see what happens.

-Tero

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCHv3 03/20] ARM: OMAP4: PM: add support for device off
  2012-06-13 15:21   ` Jean Pihet
  2012-06-14  9:18     ` Tero Kristo
@ 2012-06-14 13:53     ` Tero Kristo
  1 sibling, 0 replies; 24+ messages in thread
From: Tero Kristo @ 2012-06-14 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2012-06-13 at 17:21 +0200, Jean Pihet wrote:
> Hi Tero,
> 
> I have a few remarks regarding the genericity of this code. I think it
> is better if the code in powerdomain.c stays generic and that the
> platform specific checks and operations be moved in the specific
> functions (via the pwrdm_ops struct).

Okay, I made an alternative implementation. Compared to this:

> 
> On Tue, Jun 12, 2012 at 5:31 PM, Tero Kristo <t-kristo@ti.com> wrote:
> > On OMAP4+, device wide off-mode has its own enable mechanism in addition
> > to powerdomain target states. This patch adds support for this on top
> > of functional power states by overloading the OFF state for core pwrdm.
> > On pwrdm level, the deepest power state supported by core pwrdm is OSWR.
> > When user (e.g. suspend) programs core pwrdm target as OFF, the functional
> > power state for the domain will be OSWR with the additional device off
> > enabled. Previous power state information will reflect this also.
> >
> > Signed-off-by: Tero Kristo <t-kristo@ti.com>
> > ---
> >  arch/arm/mach-omap2/powerdomain.c           |   17 +++++++++
> >  arch/arm/mach-omap2/powerdomain.h           |   13 +++++++-
> >  arch/arm/mach-omap2/powerdomain44xx.c       |   48 +++++++++++++++++++++++++++
> >  arch/arm/mach-omap2/powerdomains44xx_data.c |    3 +-
> >  4 files changed, 79 insertions(+), 2 deletions(-)
> >

It becomes something like following. I had to implement pwrdm specific
func_ops struct, which gets set for core pwrdm. It handles the details
of device off enable / check, but I still had to hack around a bit
within the base func pwrst code to actually use the new functions. This
applies on top of the previous code, this is just a rather quick and
dirty implementation just to get some feedback. If this looks feasible,
I can change the v3 dev-off set to use this approach.

Any comments on this?

-Tero



diff --git a/arch/arm/mach-omap2/powerdomain.c
b/arch/arm/mach-omap2/powerdomain.c
index 78a9308..15926cb 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -659,6 +659,35 @@ int pwrdm_get_achievable_func_pwrst(struct
powerdomain *pwrdm, u8 func_pwrst)
 	return new_func_pwrst;
 }
 
+int pwrdm_set_next_func_pwrst(struct powerdomain *pwrdm, u32
func_pwrst)
+{
+	int pwrst, logic;
+	int next_func_pwrst;
+	int ret;
+
+	if (pwrdm->func_ops && pwrdm->func_ops->pwrdm_set_next_func_pwrst)
+		return pwrdm->func_ops->pwrdm_set_next_func_pwrst(pwrdm,
+								  func_pwrst);
+
+	pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+	logic = pwrdm_func_to_logic_pwrst(pwrdm, func_pwrst);
+	next_func_pwrst = pwrdm_read_next_func_pwrst(pwrdm);
+
+	/* Program next power state */
+	if (pwrst != pwrdm_func_to_pwrst(pwrdm, next_func_pwrst)) {
+		ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+		if (ret)
+			return ret;
+	}
+
+	/* Program RET logic state */
+	if ((pwrst == PWRDM_POWER_RET) &&
+	    (logic != pwrdm_func_to_logic_pwrst(pwrdm, next_func_pwrst)))
+		ret = pwrdm_set_logic_retst(pwrdm, logic);
+
+	return ret;
+}
+
 /* Types of sleep_switch used in omap_set_pwrdm_state */
 #define FORCEWAKEUP_SWITCH	0
 #define LOWPOWERSTATE_SWITCH	1
@@ -675,10 +704,9 @@ int pwrdm_get_achievable_func_pwrst(struct
powerdomain *pwrdm, u8 func_pwrst)
 int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 func_pwrst)
 {
 	int sleep_switch = -1, ret = 0, hwsup = 0;
-	int new_func_pwrst, next_func_pwrst, pwrst, logic;
+	int new_func_pwrst, next_func_pwrst;
+	int pwrst;
 	u8 curr_pwrst;
-	bool extra_off_enable = false;
-	bool has_extra_off = false;
 
 	if (!pwrdm || IS_ERR(pwrdm)) {
 		pr_debug("%s: invalid params: pwrdm=%p\n", __func__, pwrdm);
@@ -689,16 +717,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm,
u32 func_pwrst)
 
 	mutex_lock(&pwrdm->lock);
 
-	/* Check if powerdomain has extra off mode handling */
-	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE) {
-		has_extra_off = true;
-		if (func_pwrst == PWRDM_FUNC_PWRST_OFF)
-			extra_off_enable = true;
-	}
-
 	new_func_pwrst = pwrdm_get_achievable_func_pwrst(pwrdm, func_pwrst);
 	pwrst = pwrdm_func_to_pwrst(pwrdm, new_func_pwrst);
-	logic = pwrdm_func_to_logic_pwrst(pwrdm, new_func_pwrst);
 
 	next_func_pwrst = pwrdm_read_next_func_pwrst(pwrdm);
 	if (new_func_pwrst == next_func_pwrst)
@@ -716,25 +736,15 @@ int omap_set_pwrdm_state(struct powerdomain
*pwrdm, u32 func_pwrst)
 		}
 	}
 
-	pr_debug("%s: set func_pwrst %0x (%0x,%0x) to pwrdm %s\n",
-		 __func__, new_func_pwrst, pwrst, logic, pwrdm->name);
-
 	/* Trace the pwrdm desired target state */
 	trace_power_domain_target(pwrdm->name, new_func_pwrst,
 				  smp_processor_id());
 
-	/* Program next power state */
-	if (pwrst != pwrdm_func_to_pwrst(pwrdm, next_func_pwrst)) {
-		ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
-		if (ret)
-			pr_err("%s: unable to set power state of powerdomain: %s\n",
-			       __func__, pwrdm->name);
-	}
-
-	/* Program RET logic state */
-	if ((pwrst == PWRDM_POWER_RET) &&
-	    (logic != pwrdm_func_to_logic_pwrst(pwrdm, next_func_pwrst)))
-		pwrdm_set_logic_retst(pwrdm, logic);
+	/* Program next functional power state */
+	ret = pwrdm_set_next_func_pwrst(pwrdm, new_func_pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state of powerdomain: %s\n",
+		       __func__, pwrdm->name);
 
 	switch (sleep_switch) {
 	case FORCEWAKEUP_SWITCH:
@@ -750,9 +760,6 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm,
u32 func_pwrst)
 		break;
 	}
 
-	if (has_extra_off && arch_pwrdm->pwrdm_enable_off)
-		arch_pwrdm->pwrdm_enable_off(pwrdm, extra_off_enable);
-
 out:
 	mutex_unlock(&pwrdm->lock);
 	return ret;
@@ -819,13 +826,13 @@ int pwrdm_read_next_pwrst(struct powerdomain
*pwrdm)
  */
 int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)
 {
-	int next_pwrst = pwrdm_read_next_pwrst(pwrdm);
-	int next_logic = pwrdm_read_logic_retst(pwrdm);
+	int next_pwrst, next_logic;
 
-	if (pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE &&
-	    arch_pwrdm->pwrdm_read_next_off &&
-	    arch_pwrdm->pwrdm_read_next_off(pwrdm))
-		return PWRDM_FUNC_PWRST_OFF;
+	if (pwrdm->func_ops && pwrdm->func_ops->pwrdm_read_next_func_pwrst)
+		return pwrdm->func_ops->pwrdm_read_next_func_pwrst(pwrdm);
+
+	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+	next_logic = pwrdm_read_logic_retst(pwrdm);
 
 	return pwrdm_pwrst_to_func(pwrdm, next_pwrst, next_logic);
 }
@@ -898,12 +905,13 @@ int pwrdm_read_prev_pwrst(struct powerdomain
*pwrdm)
  */
 int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm)
 {
-	int prev_pwrst = pwrdm_read_prev_pwrst(pwrdm);
-	int prev_logic = pwrdm_read_prev_logic_pwrst(pwrdm);
+	int prev_pwrst, prev_logic;
+
+	if (pwrdm->func_ops && pwrdm->func_ops->pwrdm_read_prev_func_pwrst)
+		return pwrdm->func_ops->pwrdm_read_prev_func_pwrst(pwrdm);
 
-	if (arch_pwrdm && arch_pwrdm->pwrdm_lost_context_rff &&
-	    arch_pwrdm->pwrdm_lost_context_rff(pwrdm))
-		return PWRDM_FUNC_PWRST_OFF;
+	prev_pwrst = pwrdm_read_prev_pwrst(pwrdm);
+	prev_logic = pwrdm_read_prev_logic_pwrst(pwrdm);
 
 	return pwrdm_pwrst_to_func(pwrdm, prev_pwrst, prev_logic);
 }
diff --git a/arch/arm/mach-omap2/powerdomain.h
b/arch/arm/mach-omap2/powerdomain.h
index cc30b94..658a64b 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -76,14 +76,6 @@
 						  * powerdomain
 						  */
 /*
- * OMAP4+ has device off feature, which must be enabled separately in
- * addition to power domain next state setup. This feature is
overloaded
- * as EXTRA_OFF_ENABLE for core_pwrdm, and is implemented on top of
- * functional power state
- */
-#define PWRDM_HAS_EXTRA_OFF_ENABLE	(1 << 3)
-
-/*
  * Number of memory banks that are power-controllable.	On OMAP4430, the
  * maximum is 5.
  */
@@ -102,6 +94,20 @@ struct clockdomain;
 struct powerdomain;
 
 /**
+ * struct pwrdm_func_ops - powerdomain specific functional power state
handling
+ * @pwrdm_set_next_func_pwrst - set next functional power state
+ * @pwrdm_read_next_func_pwrst - read the next functional power state
+ * @pwrdm_read_prev_func_pwrst - read the previous functional power
state
+ * @pwrdm_clear_all_prev_func_pwrst - clear previous functional power
state
+ */
+struct pwrdm_func_ops {
+	int (*pwrdm_set_next_func_pwrst)(struct powerdomain *pwrdm, u32
state);
+	int (*pwrdm_read_next_func_pwrst)(struct powerdomain *pwrdm);
+	int (*pwrdm_read_prev_func_pwrst)(struct powerdomain *pwrdm);
+	int (*pwrdm_clear_all_prev_func_pwrst)(struct powerdomain *pwrdm);
+};
+
+/**
  * struct powerdomain - OMAP powerdomain
  * @name: Powerdomain name
  * @voltdm: voltagedomain containing this powerdomain
@@ -119,6 +125,7 @@ struct powerdomain;
  * @voltdm_node: list_head linking all powerdomains in a voltagedomain
  * @state:
  * @state_counter:
+ * @func_ops: powerdomain specific functional power states ops, if any
  * @timer:
  * @state_timer:
  *
@@ -147,6 +154,7 @@ struct powerdomain {
 	unsigned state_counter[PWRDM_MAX_FUNC_PWRSTS];
 	unsigned ret_logic_off_counter;
 	unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
+	const struct pwrdm_func_ops *func_ops;
 
 #ifdef CONFIG_PM_DEBUG
 	s64 timer;
@@ -180,9 +188,6 @@ struct powerdomain {
  * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a
pd
  * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to
deep sleep
  * @pwrdm_wait_transition: Wait for a pd state transition to complete
- * @pwrdm_lost_context_rff: Check if pd has lost RFF context (omap4+
device off)
- * @pwrdm_enable_off: Extra off mode enable for pd (omap4+ device off)
- * @pwrdm_read_next_off: Check if pd next state is off (omap4+ device
off)
  */
 struct pwrdm_ops {
 	int	(*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);
@@ -207,9 +212,6 @@ struct pwrdm_ops {
 	int	(*pwrdm_disable_hdwr_sar)(struct powerdomain *pwrdm);
 	int	(*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
 	int	(*pwrdm_wait_transition)(struct powerdomain *pwrdm);
-	bool	(*pwrdm_lost_context_rff)(struct powerdomain *pwrdm);
-	void	(*pwrdm_enable_off)(struct powerdomain *pwrdm, bool enable);
-	bool	(*pwrdm_read_next_off)(struct powerdomain *pwrdm);
 };
 
 int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
@@ -232,10 +234,14 @@ struct voltagedomain *pwrdm_get_voltdm(struct
powerdomain *pwrdm);
 
 int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
 
+int pwrdm_set_next_func_pwrst(struct powerdomain *pwrdm, u32
func_pwrst);
 int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_func_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm);
 int pwrdm_get_achievable_func_pwrst(struct powerdomain *pwrdm, u8
func_pwrst);
+int pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
+int pwrdm_func_to_logic_pwrst(struct powerdomain *pwrdm, u8
func_pwrst);
+int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic);
 
 int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8
func_pwrst);
 int omap2_pwrdm_func_to_logic_pwrst(struct powerdomain *pwrdm, u8
func_pwrst);
@@ -279,6 +285,7 @@ extern void omap44xx_powerdomains_init(void);
 extern struct pwrdm_ops omap2_pwrdm_operations;
 extern struct pwrdm_ops omap3_pwrdm_operations;
 extern struct pwrdm_ops omap4_pwrdm_operations;
+extern const struct pwrdm_func_ops omap4_core_pwrdm_func_ops;
 
 /* Common Internal functions used across OMAP rev's */
 extern u32 omap2_pwrdm_get_mem_bank_onstate_mask(u8 bank);
diff --git a/arch/arm/mach-omap2/powerdomain44xx.c
b/arch/arm/mach-omap2/powerdomain44xx.c
index b2bdc0f..ce524ed 100644
--- a/arch/arm/mach-omap2/powerdomain44xx.c
+++ b/arch/arm/mach-omap2/powerdomain44xx.c
@@ -89,12 +89,8 @@ static int omap4_pwrdm_clear_all_prev_pwrst(struct
powerdomain *pwrdm)
 					pwrdm->prcm_partition,
 					pwrdm->prcm_offs, OMAP4_PM_PWSTST);
 
-	if (pwrdm->context_offs)
-		omap4_prminst_write_inst_reg(OMAP4430_LOSTCONTEXT_DFF_MASK |
-					     OMAP4430_LOSTCONTEXT_RFF_MASK,
-					     pwrdm->prcm_partition,
-					     pwrdm->prcm_offs,
-					     pwrdm->context_offs);
+	if (pwrdm->func_ops &&
pwrdm->func_ops->pwrdm_clear_all_prev_func_pwrst)
+		return pwrdm->func_ops->pwrdm_clear_all_prev_func_pwrst(pwrdm);
 
 	return 0;
 }
@@ -336,21 +332,18 @@ static int omap4_pwrdm_disable_hdwr_sar(struct
powerdomain *pwrdm)
  * this means if the device has entered off or not. Returns true if the
  * context has been lost, false otherwise.
  */
-bool omap4_pwrdm_lost_context_rff(struct powerdomain *pwrdm)
+static bool omap4_pwrdm_lost_context_rff(struct powerdomain *pwrdm)
 {
 	u32 val;
-	s16 inst, offset;
+	s16 inst;
 
 	if (!pwrdm)
 		return false;
 
 	inst = pwrdm->prcm_offs;
-	offset = pwrdm->context_offs;
 
-	if (!offset)
-		return false;
-
-	val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, inst,
offset);
+	val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, inst,
+					  OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET);
 
 	if (val & OMAP4430_LOSTCONTEXT_RFF_MASK)
 		return true;
@@ -358,6 +351,17 @@ bool omap4_pwrdm_lost_context_rff(struct
powerdomain *pwrdm)
 	return false;
 }
 
+static int omap4_pwrdm_core_clear_all_prev_func_pwrst(struct
powerdomain *pwrdm)
+{
+	omap4_prminst_write_inst_reg(OMAP4430_LOSTCONTEXT_DFF_MASK |
+				     OMAP4430_LOSTCONTEXT_RFF_MASK,
+				     pwrdm->prcm_partition,
+				     pwrdm->prcm_offs,
+
OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET);
+
+	return 0;
+}
+
 /**
  * omap4_device_set_next_state_off - setup device off state
  * @pwrdm: struct powerdomain * to target powerdomain
@@ -367,13 +371,10 @@ bool omap4_pwrdm_lost_context_rff(struct
powerdomain *pwrdm)
  * transition to off mode as soon as all power domains in MPU, IVA
  * and CORE voltage are in OFF or OSWR state (open switch retention)
  */
-void omap4_device_set_next_state_off(struct powerdomain *pwrdm, bool
enable)
+static void omap4_device_set_next_state_off(bool enable)
 {
 	u8 val = enable ? 0x1 : 0x0;
 
-	if (!(pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE))
-		return;
-
 	omap4_prminst_write_inst_reg(val << OMAP4430_DEVICE_OFF_ENABLE_SHIFT,
 				     OMAP4430_PRM_PARTITION,
 				     OMAP4430_PRM_DEVICE_INST,
@@ -388,13 +389,10 @@ void omap4_device_set_next_state_off(struct
powerdomain *pwrdm, bool enable)
  * Checks if device off is enabled or not.
  * Returns true if enabled, false otherwise.
  */
-bool omap4_device_read_next_state_off(struct powerdomain *pwrdm)
+static bool omap4_device_read_next_state_off(void)
 {
 	u32 val;
 
-	if (!(pwrdm->flags & PWRDM_HAS_EXTRA_OFF_ENABLE))
-		return false;
-
 	val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
 					  OMAP4430_PRM_DEVICE_INST,
 					  OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET);
@@ -404,6 +402,68 @@ bool omap4_device_read_next_state_off(struct
powerdomain *pwrdm)
 	return val ? true : false;
 }
 
+static int omap4_pwrdm_core_set_next_func_pwrst(struct powerdomain
*pwrdm,
+						u32 func_pwrst)
+{
+	int pwrst, logic;
+	int next_func_pwrst;
+	int ret;
+	bool off_enable;
+
+	if (func_pwrst == PWRDM_FUNC_PWRST_OFF) {
+		off_enable = true;
+		func_pwrst = PWRDM_FUNC_PWRST_OSWR;
+	} else {
+		off_enable = false;
+	}
+
+	pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+	logic = pwrdm_func_to_logic_pwrst(pwrdm, func_pwrst);
+	next_func_pwrst = pwrdm_read_next_func_pwrst(pwrdm);
+
+	/* Program next power state */
+	if (pwrst != pwrdm_func_to_pwrst(pwrdm, next_func_pwrst)) {
+		ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+		if (ret)
+			return ret;
+	}
+
+	/* Program RET logic state */
+	if ((pwrst == PWRDM_POWER_RET) &&
+	    (logic != pwrdm_func_to_logic_pwrst(pwrdm, next_func_pwrst)))
+		ret = pwrdm_set_logic_retst(pwrdm, logic);
+
+	omap4_device_set_next_state_off(off_enable);
+
+	return ret;
+}
+
+static int omap4_pwrdm_core_read_prev_func_pwrst(struct powerdomain
*pwrdm)
+{
+	int prev_pwrst, prev_logic;
+
+	if (omap4_pwrdm_lost_context_rff(pwrdm))
+		return PWRDM_FUNC_PWRST_OFF;
+
+	prev_pwrst = pwrdm_read_prev_pwrst(pwrdm);
+	prev_logic = pwrdm_read_prev_logic_pwrst(pwrdm);
+
+	return pwrdm_pwrst_to_func(pwrdm, prev_pwrst, prev_logic);
+}
+
+static int omap4_pwrdm_core_read_next_func_pwrst(struct powerdomain
*pwrdm)
+{
+	int next_pwrst, next_logic;
+
+	if (omap4_device_read_next_state_off())
+		return PWRDM_FUNC_PWRST_OFF;
+
+	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+	next_logic = pwrdm_read_logic_retst(pwrdm);
+
+	return pwrdm_pwrst_to_func(pwrdm, next_pwrst, next_logic);
+}
+
 struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
 	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
@@ -426,7 +486,12 @@ struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_wait_transition	= omap4_pwrdm_wait_transition,
 	.pwrdm_enable_hdwr_sar	= omap4_pwrdm_enable_hdwr_sar,
 	.pwrdm_disable_hdwr_sar	= omap4_pwrdm_disable_hdwr_sar,
-	.pwrdm_lost_context_rff = omap4_pwrdm_lost_context_rff,
-	.pwrdm_enable_off	= omap4_device_set_next_state_off,
-	.pwrdm_read_next_off	= omap4_device_read_next_state_off,
+};
+
+const struct pwrdm_func_ops omap4_core_pwrdm_func_ops = {
+	.pwrdm_set_next_func_pwrst = omap4_pwrdm_core_set_next_func_pwrst,
+	.pwrdm_read_next_func_pwrst = omap4_pwrdm_core_read_next_func_pwrst,
+	.pwrdm_read_prev_func_pwrst = omap4_pwrdm_core_read_prev_func_pwrst,
+	.pwrdm_clear_all_prev_func_pwrst =
+		omap4_pwrdm_core_clear_all_prev_func_pwrst,
 };
diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c
b/arch/arm/mach-omap2/powerdomains44xx_data.c
index 13db876..7a2aad9 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -36,8 +36,7 @@ static struct powerdomain core_44xx_pwrdm = {
 	.voltdm		  = { .name = "core" },
 	.prcm_offs	  = OMAP4430_PRM_CORE_INST,
 	.prcm_partition	  = OMAP4430_PRM_PARTITION,
-	.context_offs	  = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET,
-	.pwrsts		  = PWRSTS_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 5,
 	.pwrsts_mem_ret	= {
@@ -54,8 +53,8 @@ static struct powerdomain core_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* ducati_l2ram */
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
-	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE |
-			    PWRDM_HAS_EXTRA_OFF_ENABLE,
+	.func_ops	  = &omap4_core_pwrdm_func_ops,
+	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE,
 };
 
 /* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -207,7 +206,6 @@ static struct powerdomain mpu_44xx_pwrdm = {
 	.voltdm		  = { .name = "mpu" },
 	.prcm_offs	  = OMAP4430_PRM_MPU_INST,
 	.prcm_partition	  = OMAP4430_PRM_PARTITION,
-	.context_offs	  = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET,
 	.pwrsts		  = PWRSTS_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 3,

^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2012-06-14 13:53 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-12 15:31 [PATCHv3 00/20] ARM: OMAP4: device off support Tero Kristo
2012-06-12 15:31 ` [PATCHv3 01/20] ARM: OMAP4: PM: powerdomain: Add HWSAR flag to L3INIT Tero Kristo
2012-06-12 15:31 ` [PATCHv3 02/20] ARM: OMAP4: powerdomain: update mpu / core off counters during device off Tero Kristo
2012-06-12 15:31 ` [PATCHv3 03/20] ARM: OMAP4: PM: add support for " Tero Kristo
2012-06-13 15:21   ` Jean Pihet
2012-06-14  9:18     ` Tero Kristo
2012-06-14 13:53     ` Tero Kristo
2012-06-12 15:31 ` [PATCHv3 04/20] ARM: OMAP4: PM: update ROM return address for OSWR and OFF Tero Kristo
2012-06-12 15:31 ` [PATCHv3 05/20] OMAP4: PM: clockdomain: workaround for l4_secure_clkdm HWSUP Tero Kristo
2012-06-12 15:31 ` [PATCHv3 06/20] ARM: OMAP4: secure: move GIC / wakeupgen save restore to secure CPU PM notifier Tero Kristo
2012-06-12 15:31 ` [PATCHv3 07/20] ARM: OMAP4: secure: add support for device off Tero Kristo
2012-06-12 15:31 ` [PATCHv3 08/20] ARM: OMAP4: PM: add MPUSS power domain device off support Tero Kristo
2012-06-12 15:31 ` [PATCHv3 09/20] ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode Tero Kristo
2012-06-12 15:31 ` [PATCHv3 10/20] ARM: OMAP4: PM: save/restore all CM1/2 " Tero Kristo
2012-06-12 15:31 ` [PATCHv3 11/20] ARM: OMAP4: PM: Add SAR backup support towards device OFF Tero Kristo
2012-06-12 15:31 ` [PATCHv3 12/20] ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA Tero Kristo
2012-06-12 15:31 ` [PATCHv3 13/20] ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode Tero Kristo
2012-06-12 15:31 ` [PATCHv3 14/20] ARM: OMAP4: PM: Mark the PPI and SPI interrupts as non-secure for GP Tero Kristo
2012-06-12 15:31 ` [PATCHv3 15/20] ARM: OMAP4430: PM: workaround for DDR corruption on second CS Tero Kristo
2012-06-12 15:31 ` [PATCHv3 16/20] TEMP: ARM: OMAP4: prevent voltage transitions Tero Kristo
2012-06-12 15:31 ` [PATCHv3 17/20] ARM: OMAP4: put cpu1 back to sleep if no wake request Tero Kristo
2012-06-12 15:31 ` [PATCHv3 18/20] ARM: OMAP4460: wakeupgen: set GIC_CPU0 backup status flag always Tero Kristo
2012-06-12 15:31 ` [PATCHv3 19/20] ARM: OMAP4: PM: enable off mode by default Tero Kristo
2012-06-12 15:41 ` [PATCHv3 20/20] ARM: OMAP4430: PM: errata i625, WUGEN lost for GP devices after OFF mode Tero Kristo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).