Skip to contentSkip to conversation

ARM: OMAP4 device off support

PATCH New Tero Kristo 11 participants 63 messages Apr 20, 2012 – May 11, 2012

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

cover ARM: OMAP4 device off support

Hi,

First version for this work. Applies on top of mainline + iochain set + OMAP4 core retention set. Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.4-omap4-dev-off

Tested on omap4430 EMU blaze + omap4460 GP panda boards.

Some drivers have issues with device off, most notably MMC, as it breaks device off on blaze device after 1 entry to device off mode:

[  208.906921] omap_i2c omap_i2c.1: XRDY IRQ while no data to send
[  209.905639] omap_i2c omap_i2c.1: controller timed out
[  209.905792] twl: i2c_read failed to transfer all messages
[  209.905792] omap_hsmmc omap_hsmmc.1: could not set regulator OCR (-110)
[  212.296203] mmc0: error -110 during resume (card was removed?)
[  212.562164] PM: resume of devices complete after 3656.007 msecs
[  212.660125] Restarting tasks ... done.
# 
# echo mem > /sys/power/state 
[  220.376892] PM: Syncing filesystems ... done.
[  220.382476] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  220.408386] Freezing remaining freezable tasks ... (elapsed 0.02 seconds) don
e.
[  220.439605] Suspending console(s) (use no_console_suspend to debug)
[  220.454650] dpm_run_callback(): platform_pm_suspend+0x0/0x54 returns -110
[  220.454711] PM: Device omap_hsmmc.1 failed to suspend: error -110
[  220.454711] PM: Some devices failed to suspend
[  220.718261] PM: resume of devices complete after 263.539 msecs
[  220.743988] Restarting tasks ... done.

Attempting to disable MMC from config prevented boot completely for me, so this issue is likely to stay until someone fixes the MMC driver. Panda device works fine though, although the wakeup from device off is slow due to problems with some other drivers (most likely I2C.)

Off mode is disabled by default, it can be enabled by either calling omap4_pm_enable_off_mode(1) from board files or alternatively writing to a debugfs node from userspace:

echo 1 > /debug/pm_debug/enable_off_mode

Device off entry can be tracked through the debugfs also, it increases the core_pwrdm OFF state counter / timer, as this is an invalid state for the chip normally (core enters OSWR in device off.) Not sure if this a good way to do this but comments are welcome.

-Tero

#1 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

From: Rajendra Nayak <[email protected]>

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.

---
 arch/arm/mach-omap2/cm44xx.h   |    5 +
 arch/arm/mach-omap2/dpll44xx.c |  271 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 276 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/cm44xx.h +5 -0
index 3380bee..5fba0fa 100644
@@ -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
arch/arm/mach-omap2/dpll44xx.c +271 -0

286 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#2 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Hi Tero,

On 04/20/2012 04:33 AM, Tero Kristo wrote:

[...]

Quoted 5 lines
arch/arm/mach-omap2/dpll44xx.c +5 -0
+/**
+ * omap4_dpll_print_reg - dump out a single DPLL register value
+ * @dpll_reg: register to dump
+ * @name: name of the register
+ * @tuple: content of the register

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 316

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+ *
+ * Helper dump function to print out a DPLL register value in case
+ * of restore failures.
+ */
+static void omap4_dpll_print_reg(struct omap4_dpll_regs *dpll_reg, char *name,
+				 struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		pr_warn("%s - Address offset = 0x%08x, value=0x%08x\n", name,
+			tuple->offset, tuple->val);

Minor nit-pick here ...

1. Offset is 16-bits and so we can just have "offset = 0x%04x"
2. Consider dropping "Address" from "Address offset"
3. Can we be consistent in our spaces for "offset = " and "value="?

Quoted 19 lines
arch/arm/mach-omap2/dpll44xx.c +19 -0
+}
+
+/*
+ * omap4_dpll_dump_regs - dump out DPLL registers
+ * @dpll_reg: DPLL to dump
+ *
+ * Dump out the contents of the registers for a DPLL. Called if a
+ * restore for DPLL fails to lock.
+ */
+static void omap4_dpll_dump_regs(struct omap4_dpll_regs *dpll_reg)
+{
+	pr_warn("%s: Unable to lock dpll %s[part=%x inst=%x]:\n",
+		__func__, dpll_reg->name, dpll_reg->mod_partition,
+		dpll_reg->mod_inst);
+	omap4_dpll_print_reg(dpll_reg, "clksel", &dpll_reg->clksel);
+	omap4_dpll_print_reg(dpll_reg, "div_m2", &dpll_reg->div_m2);
+	omap4_dpll_print_reg(dpll_reg, "div_m3", &dpll_reg->div_m3);
+	omap4_dpll_print_reg(dpll_reg, "div_m4", &dpll_reg->div_m4);
+	omap4_dpll_print_reg(dpll_reg, "div_m5", &dpll_reg->div_m5);

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 345

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+	omap4_dpll_print_reg(dpll_reg, "div_m6", &dpll_reg->div_m6);
+	omap4_dpll_print_reg(dpll_reg, "div_m7", &dpll_reg->div_m7);
+	omap4_dpll_print_reg(dpll_reg, "clkdcoldo", &dpll_reg->clkdcoldo);
+	omap4_dpll_print_reg(dpll_reg, "clkmode", &dpll_reg->clkmode);
+	omap4_dpll_print_reg(dpll_reg, "autoidle", &dpll_reg->autoidle);
+	if (dpll_reg->idlest.offset)
+		pr_warn("idlest - Address offset = 0x%08x, before val=0x%08x"
+			" after = 0x%08x\n", dpll_reg->idlest.offset,
+			dpll_reg->idlest.val,
+			omap4_dpll_read_reg(dpll_reg, &dpll_reg->idlest));

Nit-pick ...

1. Same comments as above
2. Consider dropping "Address offset" altogether here as we print "idlest" the offset should be implied.
3. Also can we be consistent in our naming of "before val and "after"? For example, "val before =" and "val now = ".

Cheers
Jon

#3 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 60 lines · Jon Hunter

Hi Tero,

On 04/20/2012 04:33 AM, Tero Kristo wrote:

[...]

Quoted 5 lines
arch/arm/mach-omap2/dpll44xx.c +5 -0
+/**
+ * omap4_dpll_print_reg - dump out a single DPLL register value
+ * @dpll_reg: register to dump
+ * @name: name of the register
+ * @tuple: content of the register

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 316

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+ *
+ * Helper dump function to print out a DPLL register value in case
+ * of restore failures.
+ */
+static void omap4_dpll_print_reg(struct omap4_dpll_regs *dpll_reg, char *name,
+				 struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		pr_warn("%s - Address offset = 0x%08x, value=0x%08x\n", name,
+			tuple->offset, tuple->val);

Minor nit-pick here ...

1. Offset is 16-bits and so we can just have "offset = 0x%04x"
2. Consider dropping "Address" from "Address offset"
3. Can we be consistent in our spaces for "offset = " and "value="?

Quoted 19 lines
arch/arm/mach-omap2/dpll44xx.c +19 -0
+}
+
+/*
+ * omap4_dpll_dump_regs - dump out DPLL registers
+ * @dpll_reg: DPLL to dump
+ *
+ * Dump out the contents of the registers for a DPLL. Called if a
+ * restore for DPLL fails to lock.
+ */
+static void omap4_dpll_dump_regs(struct omap4_dpll_regs *dpll_reg)
+{
+	pr_warn("%s: Unable to lock dpll %s[part=%x inst=%x]:\n",
+		__func__, dpll_reg->name, dpll_reg->mod_partition,
+		dpll_reg->mod_inst);
+	omap4_dpll_print_reg(dpll_reg, "clksel", &dpll_reg->clksel);
+	omap4_dpll_print_reg(dpll_reg, "div_m2", &dpll_reg->div_m2);
+	omap4_dpll_print_reg(dpll_reg, "div_m3", &dpll_reg->div_m3);
+	omap4_dpll_print_reg(dpll_reg, "div_m4", &dpll_reg->div_m4);
+	omap4_dpll_print_reg(dpll_reg, "div_m5", &dpll_reg->div_m5);

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 345

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+	omap4_dpll_print_reg(dpll_reg, "div_m6", &dpll_reg->div_m6);
+	omap4_dpll_print_reg(dpll_reg, "div_m7", &dpll_reg->div_m7);
+	omap4_dpll_print_reg(dpll_reg, "clkdcoldo", &dpll_reg->clkdcoldo);
+	omap4_dpll_print_reg(dpll_reg, "clkmode", &dpll_reg->clkmode);
+	omap4_dpll_print_reg(dpll_reg, "autoidle", &dpll_reg->autoidle);
+	if (dpll_reg->idlest.offset)
+		pr_warn("idlest - Address offset = 0x%08x, before val=0x%08x"
+			" after = 0x%08x\n", dpll_reg->idlest.offset,
+			dpll_reg->idlest.val,
+			omap4_dpll_read_reg(dpll_reg, &dpll_reg->idlest));

Nit-pick ...

Quoted 5 lines

1. Same comments as above
2. Consider dropping "Address offset" altogether here as we print "idlest" the offset should be implied.
3. Also can we be consistent in our naming of "before val and "after"? For example, "val before =" and "val now = ".

Okay, I'll modify both prints slightly. Question though, do we want these prints in the kernel in the first place? At least Tony has been frowning upon register dumps in the kernel and this falls into that category. What we could do is just to print the warning but drop the register dumps out.

-Tero

#4 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Hi Tero,

Quoted 67 lines · Tero Kristo
Quoted 60 lines · Jon Hunter

Hi Tero,

On 04/20/2012 04:33 AM, Tero Kristo wrote:

[...]

Quoted 5 lines
arch/arm/mach-omap2/dpll44xx.c +5 -0
+/**
+ * omap4_dpll_print_reg - dump out a single DPLL register value
+ * @dpll_reg: register to dump
+ * @name: name of the register
+ * @tuple: content of the register

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 316

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+ *
+ * Helper dump function to print out a DPLL register value in case
+ * of restore failures.
+ */
+static void omap4_dpll_print_reg(struct omap4_dpll_regs *dpll_reg, char *name,
+				 struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		pr_warn("%s - Address offset = 0x%08x, value=0x%08x\n", name,
+			tuple->offset, tuple->val);

Minor nit-pick here ...

1. Offset is 16-bits and so we can just have "offset = 0x%04x"
2. Consider dropping "Address" from "Address offset"
3. Can we be consistent in our spaces for "offset = " and "value="?

Quoted 19 lines
arch/arm/mach-omap2/dpll44xx.c +19 -0
+}
+
+/*
+ * omap4_dpll_dump_regs - dump out DPLL registers
+ * @dpll_reg: DPLL to dump
+ *
+ * Dump out the contents of the registers for a DPLL. Called if a
+ * restore for DPLL fails to lock.
+ */
+static void omap4_dpll_dump_regs(struct omap4_dpll_regs *dpll_reg)
+{
+	pr_warn("%s: Unable to lock dpll %s[part=%x inst=%x]:\n",
+		__func__, dpll_reg->name, dpll_reg->mod_partition,
+		dpll_reg->mod_inst);
+	omap4_dpll_print_reg(dpll_reg, "clksel", &dpll_reg->clksel);
+	omap4_dpll_print_reg(dpll_reg, "div_m2", &dpll_reg->div_m2);
+	omap4_dpll_print_reg(dpll_reg, "div_m3", &dpll_reg->div_m3);
+	omap4_dpll_print_reg(dpll_reg, "div_m4", &dpll_reg->div_m4);
+	omap4_dpll_print_reg(dpll_reg, "div_m5", &dpll_reg->div_m5);

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 345

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+	omap4_dpll_print_reg(dpll_reg, "div_m6", &dpll_reg->div_m6);
+	omap4_dpll_print_reg(dpll_reg, "div_m7", &dpll_reg->div_m7);
+	omap4_dpll_print_reg(dpll_reg, "clkdcoldo", &dpll_reg->clkdcoldo);
+	omap4_dpll_print_reg(dpll_reg, "clkmode", &dpll_reg->clkmode);
+	omap4_dpll_print_reg(dpll_reg, "autoidle", &dpll_reg->autoidle);
+	if (dpll_reg->idlest.offset)
+		pr_warn("idlest - Address offset = 0x%08x, before val=0x%08x"
+			" after = 0x%08x\n", dpll_reg->idlest.offset,
+			dpll_reg->idlest.val,
+			omap4_dpll_read_reg(dpll_reg, &dpll_reg->idlest));

Nit-pick ...

Quoted 5 lines

1. Same comments as above
2. Consider dropping "Address offset" altogether here as we print "idlest" the offset should be implied.
3. Also can we be consistent in our naming of "before val and "after"? For example, "val before =" and "val now = ".

Quoted 5 lines

Okay, I'll modify both prints slightly. Question though, do we want these prints in the kernel in the first place? At least Tony has been frowning upon register dumps in the kernel and this falls into that category. What we could do is just to print the warning but drop the register dumps out.

Thanks. Good question. If we are not seeing failures often, and I would hope not, probably ok to remove. However, I will let Tony comment here ...

Cheers
Jon

maintainer
#5 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 70 lines · Jon Hunter

Hi Tero,

Quoted 67 lines · Tero Kristo
Quoted 65 lines · Jon Hunter

Hi Tero,

On 04/20/2012 04:33 AM, Tero Kristo wrote:

[...]

Quoted 5 lines
arch/arm/mach-omap2/dpll44xx.c +5 -0
+/**
+ * omap4_dpll_print_reg - dump out a single DPLL register value
+ * @dpll_reg: register to dump
+ * @name: name of the register
+ * @tuple: content of the register

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 316

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+ *
+ * Helper dump function to print out a DPLL register value in case
+ * of restore failures.
+ */
+static void omap4_dpll_print_reg(struct omap4_dpll_regs *dpll_reg, char *name,
+				 struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		pr_warn("%s - Address offset = 0x%08x, value=0x%08x\n", name,
+			tuple->offset, tuple->val);

Minor nit-pick here ...

1. Offset is 16-bits and so we can just have "offset = 0x%04x"
2. Consider dropping "Address" from "Address offset"
3. Can we be consistent in our spaces for "offset = " and "value="?

Quoted 19 lines
arch/arm/mach-omap2/dpll44xx.c +19 -0
+}
+
+/*
+ * omap4_dpll_dump_regs - dump out DPLL registers
+ * @dpll_reg: DPLL to dump
+ *
+ * Dump out the contents of the registers for a DPLL. Called if a
+ * restore for DPLL fails to lock.
+ */
+static void omap4_dpll_dump_regs(struct omap4_dpll_regs *dpll_reg)
+{
+	pr_warn("%s: Unable to lock dpll %s[part=%x inst=%x]:\n",
+		__func__, dpll_reg->name, dpll_reg->mod_partition,
+		dpll_reg->mod_inst);
+	omap4_dpll_print_reg(dpll_reg, "clksel", &dpll_reg->clksel);
+	omap4_dpll_print_reg(dpll_reg, "div_m2", &dpll_reg->div_m2);
+	omap4_dpll_print_reg(dpll_reg, "div_m3", &dpll_reg->div_m3);
+	omap4_dpll_print_reg(dpll_reg, "div_m4", &dpll_reg->div_m4);
+	omap4_dpll_print_reg(dpll_reg, "div_m5", &dpll_reg->div_m5);

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 345

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+	omap4_dpll_print_reg(dpll_reg, "div_m6", &dpll_reg->div_m6);
+	omap4_dpll_print_reg(dpll_reg, "div_m7", &dpll_reg->div_m7);
+	omap4_dpll_print_reg(dpll_reg, "clkdcoldo", &dpll_reg->clkdcoldo);
+	omap4_dpll_print_reg(dpll_reg, "clkmode", &dpll_reg->clkmode);
+	omap4_dpll_print_reg(dpll_reg, "autoidle", &dpll_reg->autoidle);
+	if (dpll_reg->idlest.offset)
+		pr_warn("idlest - Address offset = 0x%08x, before val=0x%08x"
+			" after = 0x%08x\n", dpll_reg->idlest.offset,
+			dpll_reg->idlest.val,
+			omap4_dpll_read_reg(dpll_reg, &dpll_reg->idlest));

Nit-pick ...

1. Same comments as above
2. Consider dropping "Address offset" altogether here as we print "idlest" the offset should be implied.
3. Also can we be consistent in our naming of "before val and "after"? For example, "val before =" and "val now = ".

Quoted 8 lines
Quoted 5 lines

Okay, I'll modify both prints slightly. Question though, do we want these prints in the kernel in the first place? At least Tony has been frowning upon register dumps in the kernel and this falls into that category. What we could do is just to print the warning but drop the register dumps out.

Thanks. Good question. If we are not seeing failures often, and I would hope not, probably ok to remove. However, I will let Tony comment here ...

Well if the register dumps really help trace the issue and don't happen continuously I'm fine with them.

Tony

#6 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

In reply to Tero Kristo

Hi Tero,

Quoted 7 lines · Tero

From: Rajendra Nayak <[email protected]>

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.

Most of the registers being saved and restored in the various patches look to be contiguous. So, instead of a long list of these contiguous registers how about having a generic API for backup and restore of the registers contents based on the memory address range?

Most of the registers which require save and restore are either part of PRM, CM or Control. The PRM or CM instance could be passed as the base and the save/restore API could work around that.

One downside is that there are some read-only registers in between but I don't see any simple way of avoiding save and restore of those. BTW, as per the TRM that I have, this patch is also doing save and restore of some read-only registers.

Quoted 307 lines
---
 arch/arm/mach-omap2/cm44xx.h   |    5 +
 arch/arm/mach-omap2/dpll44xx.c |  271 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 276 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/cm44xx.h +5 -0
index 3380bee..5fba0fa 100644
@@ -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
arch/arm/mach-omap2/dpll44xx.c +261 -0
index 9c6a296..b411d3b 100644
@@ -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,183 @@ 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_dpll_print_reg - dump out a single DPLL register value
+ * @dpll_reg: register to dump
+ * @name: name of the register
+ * @tuple: content of the register
+ *
+ * Helper dump function to print out a DPLL register value in case
+ * of restore failures.
+ */
+static void omap4_dpll_print_reg(struct omap4_dpll_regs *dpll_reg, char *name,
+				 struct dpll_reg *tuple)
+{
+	if (tuple->offset)
+		pr_warn("%s - Address offset = 0x%08x, value=0x%08x\n", name,
+			tuple->offset, tuple->val);
+}
+
+/*
+ * omap4_dpll_dump_regs - dump out DPLL registers
+ * @dpll_reg: DPLL to dump
+ *
+ * Dump out the contents of the registers for a DPLL. Called if a
+ * restore for DPLL fails to lock.
+ */
+static void omap4_dpll_dump_regs(struct omap4_dpll_regs *dpll_reg)
+{
+	pr_warn("%s: Unable to lock dpll %s[part=%x inst=%x]:\n",
+		__func__, dpll_reg->name, dpll_reg->mod_partition,
+		dpll_reg->mod_inst);
+	omap4_dpll_print_reg(dpll_reg, "clksel", &dpll_reg->clksel);
+	omap4_dpll_print_reg(dpll_reg, "div_m2", &dpll_reg->div_m2);
+	omap4_dpll_print_reg(dpll_reg, "div_m3", &dpll_reg->div_m3);
+	omap4_dpll_print_reg(dpll_reg, "div_m4", &dpll_reg->div_m4);
+	omap4_dpll_print_reg(dpll_reg, "div_m5", &dpll_reg->div_m5);
+	omap4_dpll_print_reg(dpll_reg, "div_m6", &dpll_reg->div_m6);
+	omap4_dpll_print_reg(dpll_reg, "div_m7", &dpll_reg->div_m7);
+	omap4_dpll_print_reg(dpll_reg, "clkdcoldo", &dpll_reg->clkdcoldo);
+	omap4_dpll_print_reg(dpll_reg, "clkmode", &dpll_reg->clkmode);
+	omap4_dpll_print_reg(dpll_reg, "autoidle", &dpll_reg->autoidle);
+	if (dpll_reg->idlest.offset)
+		pr_warn("idlest - Address offset = 0x%08x, before val=0x%08x"
+			" after = 0x%08x\n", dpll_reg->idlest.offset,
+			dpll_reg->idlest.val,
+			omap4_dpll_read_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.. */
+			omap4_dpll_dump_regs(dpll_reg);
+			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);

arch/arm/mach-omap2/dpll44xx.c long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) · line 424

Quoted 10 lines
arch/arm/mach-omap2/dpll44xx.c +10 -0
+
+		/* 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);
+	}
+}

If this function is placed in SRAM and PER PLL restored just after MPU won't the exit latency be further optimized?

#7 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 16 lines · Vaibhav

Hi Tero,

Quoted 7 lines · Tero

From: Rajendra Nayak <[email protected]>

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.

Most of the registers being saved and restored in the various patches look to be contiguous. So, instead of a long list of these contiguous registers how about having a generic API for backup and restore of the registers contents based on the memory address range?

Quoted 9 lines

Most of the registers which require save and restore are either part of PRM, CM or Control. The PRM or CM instance could be passed as the base and the save/restore API could work around that.

One downside is that there are some read-only registers in between but I don't see any simple way of avoiding save and restore of those. BTW, as per the TRM that I have, this patch is also doing save and restore of some read-only registers.

You should never write to read-only registers since the behavior is undefined.

[...]

Quoted 19 lines
Quoted 19 lines
(quoted diff) +19 -0
+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);
Quoted 9 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+
+ ? ? ? ? ? ? /* Restore autoidle settings after the dpll is locked */
+ ? ? ? ? ? ? omap4_dpll_restore_reg(dpll_reg, &dpll_reg->autoidle);
+ ? ? }
+}

If this function is placed in SRAM and PER PLL restored just after MPU won't the exit latency be further optimized?

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

#8 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 21 lines · Santosh
Quoted 20 lines · Vaibhav

Hi Tero,

Quoted 7 lines · Tero

From: Rajendra Nayak <[email protected]>

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.

Most of the registers being saved and restored in the various patches look to be contiguous. So, instead of a long list of these contiguous registers how about having a generic API for backup and restore of the registers contents based on the memory address range?

Most of the registers which require save and restore are either part of PRM, CM or Control. The PRM or CM instance could be passed as the base and the save/restore API could work around that.

Quoted 7 lines
Quoted 5 lines

One downside is that there are some read-only registers in between but I don't see any simple way of avoiding save and restore of those. BTW, as per the TRM that I have, this patch is also doing save and restore of some read-only registers.

You should never write to read-only registers since the behavior is undefined.

I was afraid of that. If all the read-only registers were clubbed together a lot of code could have been removed. Looking more closely at the TRM I guess we can't really ask design folks to club those read-only registers in the future. So scratch this.

Quoted 30 lines

[...]

Quoted 19 lines
Quoted 19 lines
(quoted diff) +19 -0
+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);
Quoted 9 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+
+ ? ? ? ? ? ? /* Restore autoidle settings after the dpll is locked */
+ ? ? ? ? ? ? omap4_dpll_restore_reg(dpll_reg, &dpll_reg->autoidle);
+ ? ? }
+}

If this function is placed in SRAM and PER PLL restored just after MPU won't the exit latency be further optimized?

Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

#9 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 7 lines · Vaibhav
Quoted 6 lines · Santosh
Quoted 5 lines · Vaibhav

Hi Tero,

Quoted 2 lines · Tero

From: Rajendra Nayak <[email protected]>

[...]

Quoted 30 lines
Quoted 30 lines

[...]

Quoted 28 lines
Quoted 14 lines
(quoted diff) +14 -0
+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);

Review

Quoted 10 lines
(quoted diff) +10 -0
+
+ ? ? ? ? ? ? /* 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);
+ ? ? }
+}

If this function is placed in SRAM and PER PLL restored just after MPU won't the exit latency be further optimized?

Quoted 8 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Regards
Santosh

#10 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 5 lines
Quoted 5 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

Quoted 7 lines
Quoted 3 lines

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4. Maybe there's a extra low latency path for DDR that I am missing.

#11 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 11 lines · Vaibhav

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

Quoted 6 lines
Quoted 4 lines

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4.

Nope. It's on L4 and it is same for all OMAPs including OMAP5

Quoted 1 line

Maybe there's a extra low latency path for DDR that I am missing.

Even OMAP3 DDR is faster than OCMC RAM.

Regards
Santosh

#12 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 17 lines · Santosh
Quoted 16 lines · Vaibhav

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 12 lines
Quoted 8 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Quoted 6 lines
Quoted 1 line

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4.

Nope. It's on L4 and it is same for all OMAPs including OMAP5

Quoted 1 line

Maybe there's a extra low latency path for DDR that I am missing.

Even OMAP3 DDR is faster than OCMC RAM.

Ok. I guess I need to come up with some data for AM33x then. Thanks for the clarification.

Regards,
Vaibhav

#13 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

In reply to Bedia, Vaibhav
Quoted 13 lines · Vaibhav

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 9 lines
Quoted 9 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

Quoted 8 lines
Quoted 4 lines

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4.
Maybe there's a extra low latency path for DDR that I am missing.

have you folks considered the possibility that SRAM may be reprogrammed by Security code to almost nothing if PA/PPA size needs to be increased? it would be rather dumb not to support HS devices on which real products are made, no? rule of thumb has been to avoid usage of SRAM as it constraints security folks as well (yep, I know they should share code with all of us etc.. but they have a different sets of challenges that may deny them such luxury).

Regards,
Nishanth Menon

#14 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 22 lines · Nishanth
Quoted 13 lines · Vaibhav

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 9 lines
Quoted 9 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

Quoted 8 lines
Quoted 4 lines

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4.
Maybe there's a extra low latency path for DDR that I am missing.

Quoted 8 lines

have you folks considered the possibility that SRAM may be reprogrammed by Security code to almost nothing if PA/PPA size needs to be increased? it would be rather dumb not to support HS devices on which real products are made, no? rule of thumb has been to avoid usage of SRAM as it constraints security folks as well (yep, I know they should share code with all of us etc.. but they have a different sets of challenges that may deny them such luxury).

Even I would like to avoid the usage of MPUSS SRAM for this very reason. But AFAIK the whole PPA stuff isn't applicable for OCMC RAM (not SRAM inside MPUSS).

#15 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 32 lines · Vaibhav
Quoted 22 lines · Nishanth
Quoted 13 lines · Vaibhav

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 9 lines
Quoted 9 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

Quoted 8 lines
Quoted 4 lines

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4.
Maybe there's a extra low latency path for DDR that I am missing.

Quoted 8 lines

have you folks considered the possibility that SRAM may be reprogrammed by Security code to almost nothing if PA/PPA size needs to be increased? it would be rather dumb not to support HS devices on which real products are made, no? rule of thumb has been to avoid usage of SRAM as it constraints security folks as well (yep, I know they should share code with all of us etc.. but they have a different sets of challenges that may deny them such luxury).

Quoted 2 lines

Even I would like to avoid the usage of MPUSS SRAM for this very reason. But AFAIK the whole PPA stuff isn't applicable for OCMC RAM (not SRAM inside MPUSS).

On OMAP, even OCMC RAM can be used by security middle-ware apart from reserved SRAM
for HS/EMU devices.
That's what Nishant meant.

Regards
Santosh

#16 lore raw

PATCH 1/19 ARM: OMAP4: PM: save/restore all DPLL settings in OFF mode

Quoted 33 lines · Santosh
Quoted 32 lines · Vaibhav
Quoted 30 lines · Nishanth
Quoted 13 lines · Vaibhav

On Wed, May 02, 2012 at 16:30:26, Shilimkar, Santosh wrote:
[...]

Quoted 9 lines
Quoted 9 lines
Quoted 4 lines

How ?
SRAM is sower memory than DDR so I don't see how it will reduce latency.

I am just guessing if that's indeed the case ;)
Haven't done any measurements to really check if that's indeed the case though.

Quoted 8 lines
Quoted 4 lines

You don't have to do any real measurements at least on OMAP. OCMC RAM is interfaced over L4 and MPU has to cross two interconnect bridges to reach to SRAM. DDR is more of direct path and much faster.

Hmm, I was under the impression that OCMC RAM was on L3, at least for OMAP4.
Maybe there's a extra low latency path for DDR that I am missing.

have you folks considered the possibility that SRAM may be reprogrammed by Security code to almost nothing if PA/PPA size needs to be increased? it would be rather dumb not to support HS devices on which real products are made, no? rule of thumb has been to avoid usage of SRAM as it constraints security folks as well (yep, I know they should share code with all of us etc.. but they have a different sets of challenges that may deny them such luxury).

Quoted 8 lines
Quoted 2 lines

Even I would like to avoid the usage of MPUSS SRAM for this very reason. But AFAIK the whole PPA stuff isn't applicable for OCMC RAM (not SRAM inside MPUSS).

On OMAP, even OCMC RAM can be used by security middle-ware apart from reserved SRAM
for HS/EMU devices.
That's what Nishant meant.

Oh ok. I wasn't aware of this aspect.

Thanks,
Vaibhav

#17 lore raw

PATCH 2/19 ARM: OMAP4: PM: save/restore all CM1/2 settings in OFF mode

In reply to Tero Kristo

From: Rajendra Nayak <[email protected]>

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

---
 arch/arm/mach-omap2/cm44xx.c |  322 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/cm44xx.h |    2 +
 2 files changed, 324 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/cm44xx.c +322 -0
index 535d66e..fb5465b 100644
@@ -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,322 @@ 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 {
+	u32 mod_off;
+	u32 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,
+	{{.offset = OMAP4_CM_CM1_PROFILING_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM1_CKGEN_MOD */
+	{ .mod_off = OMAP4430_CM1_CKGEN_INST, .no_reg = 4,
+	{{.offset = OMAP4_CM_CLKSEL_CORE_OFFSET},
+	 {.offset = OMAP4_CM_CLKSEL_ABE_OFFSET},
+	 {.offset = OMAP4_CM_DLL_CTRL_OFFSET},
+	 {.offset = OMAP4_CM_DYN_DEP_PRESCAL_OFFSET} },
+	},
+	/* OMAP4430_CM1_MPU_MOD */
+	{ .mod_off = OMAP4430_CM1_MPU_INST, .no_reg = 4,
+	{{.offset = OMAP4_CM_MPU_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MPU_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_MPU_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_MPU_MPU_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM1_TESLA_MOD */
+	{ .mod_off = OMAP4430_CM1_TESLA_INST, .no_reg = 4,
+	{{.offset = OMAP4_CM_TESLA_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_TESLA_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_TESLA_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM1_ABE_MOD */
+	{ .mod_off = OMAP4430_CM1_ABE_INST, .no_reg = 15,
+	{{.offset = OMAP4_CM1_ABE_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_AESS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_PDM_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_DMIC_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_MCBSP1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_MCBSP2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_MCBSP3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_SLIMBUS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_TIMER5_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_TIMER6_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_TIMER7_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM1_ABE_TIMER8_CLKCTRL_OFFSET},
+	 {.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,
+	{{.offset = OMAP4_CM_CM2_PROFILING_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_CKGEN_MOD */
+	{.mod_off = OMAP4430_CM2_CKGEN_INST, .no_reg = 12,
+	{{.offset = OMAP4_CM_CLKSEL_DUCATI_ISS_ROOT_OFFSET},
+	 {.offset = OMAP4_CM_CLKSEL_USB_60MHZ_OFFSET},
+	 {.offset = OMAP4_CM_SCALE_FCLK_OFFSET},
+	 {.offset = OMAP4_CM_CORE_DVFS_PERF1_OFFSET},
+	 {.offset = OMAP4_CM_CORE_DVFS_PERF2_OFFSET},
+	 {.offset = OMAP4_CM_CORE_DVFS_PERF3_OFFSET},
+	 {.offset = OMAP4_CM_CORE_DVFS_PERF4_OFFSET},
+	 {.offset = OMAP4_CM_CORE_DVFS_CURRENT_OFFSET},
+	 {.offset = OMAP4_CM_IVA_DVFS_PERF_TESLA_OFFSET},
+	 {.offset = OMAP4_CM_IVA_DVFS_PERF_IVAHD_OFFSET},
+	 {.offset = OMAP4_CM_IVA_DVFS_PERF_ABE_OFFSET},
+	 {.offset = OMAP4_CM_IVA_DVFS_CURRENT_OFFSET} },
+	},
+	/* OMAP4430_CM2_ALWAYS_ON_MOD */
+	{.mod_off = OMAP4430_CM2_ALWAYS_ON_INST, .no_reg = 6,
+	{{.offset = OMAP4_CM_ALWON_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_ALWON_MDMINTC_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_ALWON_USBPHY_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_CORE_MOD */
+	{.mod_off = OMAP4430_CM2_CORE_INST, .no_reg = 41,
+	{{.offset = OMAP4_CM_L3_1_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3_1_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L3_1_L3_1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3_2_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3_2_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L3_2_L3_2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3_2_GPMC_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3_2_OCMC_RAM_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_DUCATI_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_DUCATI_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_SDMA_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_SDMA_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_SDMA_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_SDMA_SDMA_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_EMIF_FW_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_EMIF_1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_EMIF_2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_DLL_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_EMIF_H1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_EMIF_H2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_MEMIF_DLL_H_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_D2D_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_D2D_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_D2D_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_D2D_SAD2D_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_D2D_MODEM_ICR_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_D2D_SAD2D_FW_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4CFG_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4CFG_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4CFG_HW_SEM_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4CFG_SAR_ROM_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INSTR_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INSTR_L3_3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_IVAHD_MOD */
+	{.mod_off = OMAP4430_CM2_IVAHD_INST, .no_reg = 5,
+	{{.offset = OMAP4_CM_IVAHD_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_IVAHD_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_IVAHD_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_IVAHD_IVAHD_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_CAM_MOD */
+	{.mod_off = OMAP4430_CM2_CAM_INST, .no_reg = 5,
+	{{.offset = OMAP4_CM_CAM_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_CAM_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_CAM_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_DSS_MOD */
+	{.mod_off = OMAP4430_CM2_DSS_INST, .no_reg = 5,
+	{{.offset = OMAP4_CM_DSS_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_DSS_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_DSS_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_DSS_DEISS_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_GFX_MOD */
+	{.mod_off = OMAP4430_CM2_GFX_INST, .no_reg = 4,
+	{{.offset = OMAP4_CM_GFX_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_GFX_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_GFX_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_L3INIT_MOD */
+	{.mod_off = OMAP4430_CM2_L3INIT_INST, .no_reg = 20,
+	{{.offset = OMAP4_CM_L3INIT_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_MMC1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_MMC2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_HSI_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_UNIPRO1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_USB_OTG_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_P1500_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_EMAC_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_SATA_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_TPPSS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_PCIESS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_CCPTX_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_XHPI_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_MMC6_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_USB_HOST_FS_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_L4PER_MOD */
+	{.mod_off = OMAP4430_CM2_L4PER_INST, .no_reg = 51,
+	{{.offset = OMAP4_CM_L4PER_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_ADC_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DMTIMER10_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DMTIMER11_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DMTIMER2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DMTIMER3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DMTIMER4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_DMTIMER9_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_ELM_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_GPIO2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_GPIO3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_GPIO4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_GPIO5_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_GPIO6_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_HECC1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_HECC2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_I2C1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_I2C2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_I2C3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_I2C4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_L4PER_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCASP2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCASP3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCBSP4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MGATE_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCSPI1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCSPI2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCSPI3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MCSPI4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MMCSD3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MMCSD4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MSPROHG_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_SLIMBUS2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_UART1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_UART2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_UART3_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_UART4_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_MMCSD5_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4PER_I2C5_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_STATICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_DYNAMICDEP_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_AES1_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_AES2_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_DES3DES_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_PKAEIP29_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_RNG_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_SHA2MD51_CLKCTRL_OFFSET},
+	 {.offset = OMAP4_CM_L4SEC_CRYPTODMA_CLKCTRL_OFFSET} },
+	},
+	/* OMAP4430_CM2_CEFUSE_MOD */
+	{.mod_off = OMAP4430_CM2_CEFUSE_INST, .no_reg = 2,
+	{{.offset = OMAP4_CM_CEFUSE_CLKSTCTRL_OFFSET},
+	 {.offset = OMAP4_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET} },
+	},
+};
+
+static void omap4_cm1_prepare_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm1_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(OMAP4430_CM1_PARTITION,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm2_prepare_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm2_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm1_resume_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm1_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    OMAP4430_CM1_PARTITION,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm2_resume_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm2_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    OMAP4430_CM2_PARTITION,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}
+
+void omap4_cm_prepare_off(void)
+{
+	omap4_cm1_prepare_off();
+	omap4_cm2_prepare_off();
+}
+
+void omap4_cm_resume_off(void)
+{
+	omap4_cm1_resume_off();
+	omap4_cm2_resume_off();
+}
arch/arm/mach-omap2/cm44xx.h +2 -0
index 5fba0fa..b3b0f21 100644
@@ -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
Signature · 1 line
1.7.4.1
#18 lore raw

PATCH 2/19 ARM: OMAP4: PM: save/restore all CM1/2 settings in OFF mode

Quoted 3 lines · Tero Kristo

From: Rajendra Nayak <[email protected]>

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

Except they are still lost since nobody calls these new functions (in this patch.) :)

For ease of review, it's preferred to add the *users* of new code in the same patch as the new code.

Quoted 32 lines
---
 arch/arm/mach-omap2/cm44xx.c |  322 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/cm44xx.h |    2 +
 2 files changed, 324 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/cm44xx.c +4 -0
index 535d66e..fb5465b 100644
@@ -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,322 @@ void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg)
 {
 	__raw_writel(val, OMAP44XX_CM2_REGADDR(inst, reg));
 }
+

arch/arm/mach-omap2/cm44xx.c void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) · line 66

Quoted 10 lines
arch/arm/mach-omap2/cm44xx.c +10 -0
+#define MAX_CM_REGISTERS 51
+
+struct omap4_cm_reg {
+	u16 offset;
+	u32 val;
+};
+
+struct omap4_cm_regs {
+	u32 mod_off;
+	u32 no_reg;

minor: do these need to be u32?

arch/arm/mach-omap2/cm44xx.c void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) · line 73

Quoted 7 lines
arch/arm/mach-omap2/cm44xx.c +7 -0
+	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,
+	{{.offset = OMAP4_CM_CM1_PROFILING_CLKCTRL_OFFSET} },

For readability sake, I'd prefer to see this line indented. And why the extra space before the final '}'}

Quoted 1 line
arch/arm/mach-omap2/cm44xx.c +1 -0
+	},

[...]

Quoted 49 lines
arch/arm/mach-omap2/cm44xx.c +48 -0
+static void omap4_cm1_prepare_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm1_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(OMAP4430_CM1_PARTITION,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm2_prepare_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm2_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
 
+static void omap4_cm1_resume_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm1_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    OMAP4430_CM1_PARTITION,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm2_resume_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm2_regs;

arch/arm/mach-omap2/cm44xx.c void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) · line 362

Quoted 10 lines
arch/arm/mach-omap2/cm44xx.c +10 -0
+
+	for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    OMAP4430_CM2_PARTITION,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}

Notice the two prpare functions (and resume functions) are basically identical, except for the partition.

How about adding a .partition field to the struct so there can be a single function}

Kevin

#19 lore raw

PATCH 2/19 ARM: OMAP4: PM: save/restore all CM1/2 settings in OFF mode

Quoted 11 lines · Kevin Hilman
Quoted 3 lines · Tero Kristo

From: Rajendra Nayak <[email protected]>

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

Except they are still lost since nobody calls these new functions (in this patch.) :)

For ease of review, it's preferred to add the *users* of new code in the same patch as the new code.

I'll fix this for the next version. I think this same comment applies to patch #3 also.

Quoted 37 lines
Quoted 37 lines
---
 arch/arm/mach-omap2/cm44xx.c |  322 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/cm44xx.h |    2 +
 2 files changed, 324 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/cm44xx.c +8 -0
index 535d66e..fb5465b 100644
@@ -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,322 @@ 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;
Quoted 8 lines

arch/arm/mach-omap2/cm44xx.c void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) · line 66

Quoted 6 lines
arch/arm/mach-omap2/cm44xx.c +6 -0
+	u32 val;
+};
+
+struct omap4_cm_regs {
+	u32 mod_off;
+	u32 no_reg;

minor: do these need to be u32?

u16 should be good enough to save space I guess, I'll try changing this and see what happens.

Quoted 11 lines

arch/arm/mach-omap2/cm44xx.c void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) · line 73

Quoted 8 lines
arch/arm/mach-omap2/cm44xx.c +7 -0
+	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,
+	{{.offset = OMAP4_CM_CM1_PROFILING_CLKCTRL_OFFSET} },

For readability sake, I'd prefer to see this line indented. And why the extra space before the final '}'}

These tables are horrible, would be better to get rid of them completely but I guess that is not possible... I'll look at the indentation.

Quoted 68 lines
Quoted 2 lines
arch/arm/mach-omap2/cm44xx.c +1 -0
+	},

[...]

Quoted 49 lines
arch/arm/mach-omap2/cm44xx.c +48 -0
+static void omap4_cm1_prepare_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm1_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(OMAP4430_CM1_PARTITION,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm2_prepare_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm2_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			cm_reg->reg[j].val =
+			    omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+						       cm_reg->mod_off,
+						       cm_reg->reg[j].offset);
+		}
+	}
+}
 
+static void omap4_cm1_resume_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm1_regs;
+
+	for (i = 0; i < ARRAY_SIZE(cm1_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    OMAP4430_CM1_PARTITION,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}
+
+static void omap4_cm2_resume_off(void)
+{
+	u32 i, j;
+	struct omap4_cm_regs *cm_reg = cm2_regs;

arch/arm/mach-omap2/cm44xx.c void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) · line 362

Quoted 10 lines
arch/arm/mach-omap2/cm44xx.c +10 -0
+
+	for (i = 0; i < ARRAY_SIZE(cm2_regs); i++, cm_reg++) {
+		for (j = 0; j < cm_reg->no_reg; j++) {
+			omap4_cminst_write_inst_reg(cm_reg->reg[j].val,
+						    OMAP4430_CM2_PARTITION,
+						    cm_reg->mod_off,
+						    cm_reg->reg[j].offset);
+		}
+	}
+}

Notice the two prpare functions (and resume functions) are basically identical, except for the partition.

Quoted 2 lines

How about adding a .partition field to the struct so there can be a single function}

Yea, should be possible. I'll fix this for next rev.

-Tero

#20 lore raw

PATCH 3/19 ARM: OMAP4: PM: powerdomain: Add HWSAR flag to L3INIT

In reply to Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

---
 arch/arm/mach-omap2/powerdomain44xx.c       |   41 +++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomains44xx_data.c |    2 +-
 2 files changed, 42 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/powerdomain44xx.c +41 -0
index 601325b..9bfb8a0 100644
@@ -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)
 {
@@ -208,6 +212,41 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 	return 0;
 }
 
+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;
+}
+
+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_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
@@ -223,4 +262,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,
 };
arch/arm/mach-omap2/powerdomains44xx_data.c +1 -1
index 704664c..d8701ce 100644
@@ -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 */
Signature · 1 line
1.7.4.1
#21 lore raw

PATCH 4/19 ARM: OMAP4: Add SAR ROM base address

In reply to Tero Kristo

Added in preparation for device off mode. SAR ROM contains the mapping from SAR RAM to IO registers, and this will eventually be parsed during init time to do the reverse before device off.

---
 arch/arm/plat-omap/include/plat/omap44xx.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/plat-omap/include/plat/omap44xx.h +1 -0
index c0d478e..1a45700 100644
@@ -46,6 +46,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)
Signature · 1 line
1.7.4.1
#22 lore raw

PATCH 5/19 ARM: OMAP4: PM: Add SAR backup support towards device OFF

In reply to Tero Kristo

From: Santosh Shilimkar <[email protected]>

The SAR RAM is maintained during Device OFF mode. The register layout is fixed in SAR ROM. 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.

[with contributions for 4460, cleanups from:
Rajeev Kulkarni <[email protected]>
Nishanth Menon <[email protected]>
Axel Haslam <[email protected]>
Avinash.H.M <[email protected]>]

[t-kristo at ti.com: dropped huge data tables as they are no longer needed
with subsequent patches that generate the layouts based on SAR ROM contents, also dropped unnecessary dmm-44xx.h header file.]

---
 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-sar.c             |  341 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/omap4-common.c         |   28 ---
 arch/arm/mach-omap2/omap4-sar-layout.h     |   50 ++++
 arch/arm/mach-omap2/pm.h                   |   12 +
 arch/arm/plat-omap/include/plat/omap44xx.h |    5 +
 8 files changed, 413 insertions(+), 29 deletions(-)
 create mode 100644 arch/arm/mach-omap2/omap-sar.c
arch/arm/mach-omap2/Makefile +1 -1
index 49f92bc..a978679 100644
@@ -27,7 +27,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 \
-					   sleep44xx.o
+					   sleep44xx.o omap-sar.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_omap-headsmp.o			:=-Wa,-march=armv7-a$(plus_sec)
arch/arm/mach-omap2/cm1_44xx.h +2 -0
index 1bc00dc..c21b660 100644
@@ -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
arch/arm/mach-omap2/cm2_44xx.h +2 -0
index b9de72d..3e8871e 100644
@@ -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
arch/arm/mach-omap2/omap-sar.c new file +341 -0

341 lines not on this page · raw message

arch/arm/mach-omap2/omap4-common.c +0 -28
index cc6a915..7ea4652 100644
@@ -37,7 +37,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
@@ -186,30 +185,3 @@ 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);
arch/arm/mach-omap2/omap4-sar-layout.h +50 -0

56 lines not on this page · raw message

arch/arm/mach-omap2/pm.h +12 -0
index 07ad800..c13e3c1 100644
@@ -138,4 +138,16 @@ static inline int omap4_twl_init(void)
 }
 #endif
 
+#ifdef CONFIG_PM
+extern int omap4_sar_save(void);
+extern void omap4_sar_overwrite(void);
+#else
+static inline void omap4_sar_save(void)
+{
+}
+static inline void omap4_sar_overwrite(void)
+{
+}
+#endif
+
 #endif
arch/arm/plat-omap/include/plat/omap44xx.h +5 -0
index 1a45700..8e83e16 100644
@@ -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
@@ -59,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 */
 
Signature · 1 line
1.7.4.1
maintainer
#23 lore raw

PATCH 5/19 ARM: OMAP4: PM: Add SAR backup support towards device OFF

Quoted 9 lines · Tero Kristo
arch/arm/mach-omap2/omap-sar.c new file +9 -0
+
+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.

arch/arm/mach-omap2/omap-sar.c line 126

Quoted 10 lines
arch/arm/mach-omap2/omap-sar.c new file +10 -0
+	 */
+	usbhost_state = omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+						   OMAP4430_CM2_L3INIT_INST,
+						   OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET)
+	    & (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)
+	    & OMAP4430_IDLEST_MASK;

Formatting here looks bad, maybe just do it in separate steps:

	usbhost_state = omap4_cminst...
	usbhost_state &= OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK;

...

arch/arm/mach-omap2/omap-sar.c line 149

Quoted 7 lines
arch/arm/mach-omap2/omap-sar.c new file +7 -0
+	/*
+	 * 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 -ENODEV;
+	}

Everytime there's SoC/hardware revision detection in a non __init function, something is most likely wrong.

arch/arm/mach-omap2/omap-sar.c line 203

Quoted 7 lines
arch/arm/mach-omap2/omap-sar.c new file +7 -0
+void omap4_sar_overwrite(void)
+{
+	u32 val = 0;
+	u32 offset = 0;
+
+	if (cpu_is_omap446x())
+		offset = 0x04;

Here too.

arch/arm/mach-omap2/omap-sar.c line 267

Quoted 8 lines
arch/arm/mach-omap2/omap-sar.c new file +8 -0
+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;

You should configure things here instead by setting function pointers or variables.

Regards,

Tony

#24 lore raw

PATCH 5/19 ARM: OMAP4: PM: Add SAR backup support towards device OFF

Quoted 63 lines · Tony Lindgren
Quoted 9 lines · Tero Kristo
arch/arm/mach-omap2/omap-sar.c new file +9 -0
+
+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.

arch/arm/mach-omap2/omap-sar.c line 126

Quoted 10 lines
arch/arm/mach-omap2/omap-sar.c new file +10 -0
+	 */
+	usbhost_state = omap4_cminst_read_inst_reg(OMAP4430_CM2_PARTITION,
+						   OMAP4430_CM2_L3INIT_INST,
+						   OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET)
+	    & (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)
+	    & OMAP4430_IDLEST_MASK;

Formatting here looks bad, maybe just do it in separate steps:

	usbhost_state = omap4_cminst...
	usbhost_state &= OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK;

...

arch/arm/mach-omap2/omap-sar.c line 149

Quoted 7 lines
arch/arm/mach-omap2/omap-sar.c new file +7 -0
+	/*
+	 * 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 -ENODEV;
+	}

Everytime there's SoC/hardware revision detection in a non __init function, something is most likely wrong.

arch/arm/mach-omap2/omap-sar.c line 203

Quoted 7 lines
arch/arm/mach-omap2/omap-sar.c new file +7 -0
+void omap4_sar_overwrite(void)
+{
+	u32 val = 0;
+	u32 offset = 0;
+
+	if (cpu_is_omap446x())
+		offset = 0x04;

Here too.

arch/arm/mach-omap2/omap-sar.c line 267

Quoted 8 lines
arch/arm/mach-omap2/omap-sar.c new file +8 -0
+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;

You should configure things here instead by setting function pointers or variables.

Quoted 3 lines

Regards,

Tony

Okay, I can drop rest of these from this patch, most of them do not exist in the final code (removed by later patches for autogeneration), I just left this here for historical reasons.

-Tero

#25 lore raw

PATCH 6/19 ARM: OMAP4: Auto generate SAR layout contents

In reply to Tero Kristo

SAR layout contents are now generated automatically based on SAR ROM contents during boot.

u32 offset description
---------- -------------------------
0 pointer to next entry
1 size of DMA transfer in bytes
2 SAR RAM address for save / restore
3 IO address for save / restore

sar_layout_generate() parses this info and stores the resulting data to a list of sar_ram_entry structs, which in turn will be used by sar_save.

---
 arch/arm/mach-omap2/omap-sar.c |  290 +++++++++++++++++++++++++++-------------
 1 files changed, 194 insertions(+), 96 deletions(-)
arch/arm/mach-omap2/omap-sar.c +194 -96
index 74e0207..da4696a 100644
@@ -2,7 +2,8 @@
  * OMAP4 Save Restore source file
  *
  * Copyright (C) 2010 Texas Instruments, Inc.
- * Written by Santosh Shilimkar <[email protected]>
+ * Santosh Shilimkar <[email protected]>
+ * Tero Kristo <[email protected]>
  *
  * 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
@@ -14,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/slab.h>
 
 #include "iomap.h"
 #include "pm.h"
@@ -25,35 +27,18 @@
 #include "cminst44xx.h"
 
 static void __iomem *sar_ram_base;
-static void __iomem *omap4_sar_modules[MAX_SAR_MODULES];
 static struct powerdomain *l3init_pwrdm;
 	static struct clockdomain *l3init_clkdm;
 static struct clk *usb_host_ck, *usb_tll_ck;
 
-/*
- * SAR_RAM1 register layout consist of EMIF1, EMIF2, CM1, CM2,
- * CONTROL_CORE efuse, DMM and USB TLL registers.
- * The layout is arranged is a two dimentional array like
- * below,
- * const u32 sar_ramX_layout[nb_regs_sets][4] = {
- *	{module_index, reg_offset, size, sar_ram_offset},
- * }
- */
-static const u32 omap443x_sar_ram1_layout[][4] = {
-};
-
-/*
- * SAR_RAM2 register layout consist of SYSCTRL_PADCONF_CORE regsiters
- */
-static const u32 omap443x_sar_ram2_layout[][4] = {
+struct sar_ram_entry {
+	void __iomem *io_base;
+	u32 offset;
+	u32 size;
+	u32 ram_addr;
 };
 
-/*
- * SAR_RAM3 and  SAR_RAM4 layout is not listed since moslty it's handle by
- * secure software.
- */
-static const u32 omap443x_sar_ram3_layout[][4] = {
-};
+static struct sar_ram_entry *sar_ram_layout[3];
 
 /*
  * omap_sar_save :
@@ -63,25 +48,20 @@ static const u32 omap443x_sar_ram3_layout[][4] = {
  * @sar_bank_offset - where to backup
  * @sar_layout - constant table containing the backup info
  */
-static void sar_save(u32 nb_regs, u32 sar_bank, const u32 sar_layout_table[][4])
+static void sar_save(struct sar_ram_entry *entry)
 {
-	u32 reg_val, size, i, j;
+	u32 reg_val, size, i;
 	void __iomem *reg_read_addr, *sar_wr_addr;
 
-	for (i = 0; i < nb_regs; i++) {
-		if (omap4_sar_modules[(sar_layout_table[i][MODULE_ADDR_IDX])]) {
-			size = sar_layout_table[i][MODULE_NB_REGS_IDX];
-			reg_read_addr =
-			    omap4_sar_modules[sar_layout_table[i]
-					      [MODULE_ADDR_IDX]]
-			    + sar_layout_table[i][MODULE_OFFSET_IDX];
-			sar_wr_addr = sar_ram_base + sar_bank +
-			    sar_layout_table[i][SAR_RAM_OFFSET_IDX];
-			for (j = 0; j < size; j++) {
-				reg_val = __raw_readl(reg_read_addr + j * 4);
-				__raw_writel(reg_val, sar_wr_addr + j * 4);
-			}
+	while (entry->size) {
+		size = entry->size;
+		reg_read_addr = entry->io_base + entry->offset;
+		sar_wr_addr = sar_ram_base + entry->ram_addr;
+		for (i = 0; i < size; i++) {
+			reg_val = __raw_readl(reg_read_addr + i * 4);
+			__raw_writel(reg_val, sar_wr_addr + i * 4);
 		}
+		entry++;
 	}
 }
 
@@ -100,8 +80,7 @@ static void save_sar_bank3(void)
 	l4_secure_clkdm = clkdm_lookup("l4_secure_clkdm");
 	clkdm_wakeup(l4_secure_clkdm);
 
-	sar_save(ARRAY_SIZE(omap443x_sar_ram3_layout), SAR_BANK3_OFFSET,
-		 omap443x_sar_ram3_layout);
+	sar_save(sar_ram_layout[2]);
 
 	clkdm_allow_idle(l4_secure_clkdm);
 }
@@ -116,13 +95,13 @@ static int omap4_sar_not_accessible(void)
 	 * 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)
+				OMAP4430_CM2_L3INIT_INST,
+				OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET)
 	    & (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)
+				OMAP4430_CM2_L3INIT_INST,
+				OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET)
 	    & OMAP4430_IDLEST_MASK;
 
 	if ((usbhost_state == (OMAP4430_STBYST_MASK | OMAP4430_IDLEST_MASK)) &&
@@ -133,12 +112,12 @@ static int omap4_sar_not_accessible(void)
 }
 
  /*
-  * omap4_sar_save -
+  * omap_sar_save -
   * Save the context to SAR_RAM1 and SAR_RAM2 as per
   * omap4xxx_sar_ram1_layout and omap4xxx_sar_ram2_layout for the device OFF
   * mode
   */
-int omap4_sar_save(void)
+int omap_sar_save(void)
 {
 	/*
 	 * Not supported on ES1.0 silicon
@@ -163,8 +142,7 @@ int omap4_sar_save(void)
 	clk_enable(usb_tll_ck);
 
 	/* Save SAR BANK1 */
-	sar_save(ARRAY_SIZE(omap443x_sar_ram1_layout), SAR_BANK1_OFFSET,
-		 omap443x_sar_ram1_layout);
+	sar_save(sar_ram_layout[0]);
 
 	clk_disable(usb_host_ck);
 	clk_disable(usb_tll_ck);
@@ -172,8 +150,7 @@ int omap4_sar_save(void)
 	clkdm_allow_idle(l3init_clkdm);
 
 	/* Save SAR BANK2 */
-	sar_save(ARRAY_SIZE(omap443x_sar_ram2_layout), SAR_BANK2_OFFSET,
-		 omap443x_sar_ram2_layout);
+	sar_save(sar_ram_layout[1]);
 
 	return 0;
 }
@@ -194,13 +171,16 @@ int omap4_sar_save(void)
  *		sequencing, the software must overwrite data read from
  *		the following registers implied in phase2a and phase 2b
  */
-void omap4_sar_overwrite(void)
+void omap_sar_overwrite(void)
 {
 	u32 val = 0;
-	u32 offset = 0;
+	u32 usb_offset = 0x2ec;
+	u32 usb_offset2 = 0x91c;
 
-	if (cpu_is_omap446x())
-		offset = 0x04;
+	if (cpu_is_omap446x()) {
+		usb_offset = 0x2f4;
+		usb_offset2 = 0x920;
+	}
 
 	/* Overwriting Phase1 data to be restored */
 	/* CM2 MEMIF_CLKTRCTRL = SW_WKUP, before FREQ UPDATE */
@@ -215,7 +195,7 @@ void omap4_sar_overwrite(void)
 	/* CM1 CM_SHADOW_FREQ_CONFIG1, Enable FREQ UPDATE */
 	val = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1);
 	val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT;
-	val &= ~OMAP4430_DLL_OVERRIDE_MASK;
+	val &= ~OMAP4430_DLL_OVERRIDE_2_2_MASK;
 	__raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + 0x104);
 	/* CM2 MEMIF_CLKTRCTRL = HW_AUTO, after FREQ UPDATE */
 	__raw_writel(0x3, sar_ram_base + SAR_BANK1_OFFSET + 0x124);
@@ -223,29 +203,29 @@ void omap4_sar_overwrite(void)
 	/* Overwriting Phase2a data to be restored */
 	/* CM_L3INIT_USB_HOST_CLKCTRL: SAR_MODE = 1, MODULEMODE = 2 */
 	__raw_writel(0x00000012,
-		     sar_ram_base + SAR_BANK1_OFFSET + 0x2ec + offset);
+		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset);
 	/* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 1, MODULEMODE = 1 */
 	__raw_writel(0x00000011,
-		     sar_ram_base + SAR_BANK1_OFFSET + 0x2f0 + offset);
+		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset + 4);
 	/* CM2 CM_SDMA_STATICDEP : Enable static depedency for SAR modules */
 	__raw_writel(0x000090e8,
-		     sar_ram_base + SAR_BANK1_OFFSET + 0x2f4 + offset);
+		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset + 8);
 
 	/* 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 + SAR_BANK1_OFFSET + 0x91c + offset);
+	__raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + usb_offset2);
 	/* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 0, MODULEMODE = 0 */
 	__raw_writel(0x0000000,
-		     sar_ram_base + SAR_BANK1_OFFSET + 0x920 + offset);
+		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset2 + 4);
 	/* CM2 CM_SDMA_STATICDEP : Clear the static depedency */
 	__raw_writel(0x00000040,
-		     sar_ram_base + SAR_BANK1_OFFSET + 0x924 + offset);
+		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset2 + 8);
 
 	/* readback to ensure data reaches to SAR RAM */
 	barrier();
-	val = __raw_readl(sar_ram_base + SAR_BANK1_OFFSET + 0x924 + offset);
+	val = __raw_readl(sar_ram_base + SAR_BANK1_OFFSET + usb_offset2 + 8);
 }
 
 void __iomem *omap4_get_sar_ram_base(void)
@@ -253,6 +233,152 @@ void __iomem *omap4_get_sar_ram_base(void)
 	return sar_ram_base;
 }
 
+static const u32 sar_rom_phases[] = {
+	0, 0x30, 0x60
+};
+
+struct sar_module {
+	void __iomem *io_base;
+	u32 base;
+	u32 size;
+	bool invalid;
+};
+
+static struct sar_module *sar_modules;
+
+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);
+			BUG_ON(!mod->io_base);
+		}
+		mod++;
+	}
+}
+
+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;
+}
+
+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 */
+	sarram = kmalloc(SAR_BANK4_OFFSET, GFP_KERNEL);
+	for (bank = 0; bank < 3; bank++)
+		entry[bank] = sarram + SAR_BANK2_OFFSET * bank;
+
+	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;
+				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;
+					entry[bank]++;
+				}
+			}
+
+			if (next < rombase || next > romend)
+				break;
+
+			offset = next - rombase;
+		}
+	}
+
+	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;
+}
+
+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 },
+};
+
 /*
  * SAR RAM used to save and restore the HW
  * context in low power modes
@@ -273,39 +399,11 @@ static int __init omap4_sar_ram_init(void)
 	sar_ram_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K);
 	BUG_ON(!sar_ram_base);
 
-	/*
-	 * All these are static mappings so ioremap() will
-	 * just return with mapped VA
-	 */
-	omap4_sar_modules[EMIF1_INDEX] = ioremap(OMAP44XX_EMIF1_BASE, SZ_1M);
-	BUG_ON(!omap4_sar_modules[EMIF1_INDEX]);
-	omap4_sar_modules[EMIF2_INDEX] = ioremap(OMAP44XX_EMIF2_BASE, SZ_1M);
-	BUG_ON(!omap4_sar_modules[EMIF2_INDEX]);
-	omap4_sar_modules[DMM_INDEX] = ioremap(OMAP44XX_DMM_BASE, SZ_1M);
-	BUG_ON(!omap4_sar_modules[DMM_INDEX]);
-	omap4_sar_modules[CM1_INDEX] = ioremap(OMAP4430_CM1_BASE, SZ_8K);
-	BUG_ON(!omap4_sar_modules[CM1_INDEX]);
-	omap4_sar_modules[CM2_INDEX] = ioremap(OMAP4430_CM2_BASE, SZ_8K);
-	BUG_ON(!omap4_sar_modules[CM2_INDEX]);
-	omap4_sar_modules[C2C_INDEX] = ioremap(OMAP44XX_C2C_BASE, SZ_1M);
-	BUG_ON(!omap4_sar_modules[C2C_INDEX]);
-	omap4_sar_modules[CTRL_MODULE_PAD_CORE_INDEX] =
-	    ioremap(OMAP443X_CTRL_BASE, SZ_4K);
-	BUG_ON(!omap4_sar_modules[CTRL_MODULE_PAD_CORE_INDEX]);
-	omap4_sar_modules[L3_CLK1_INDEX] = ioremap(L3_44XX_BASE_CLK1, SZ_1M);
-	BUG_ON(!omap4_sar_modules[L3_CLK1_INDEX]);
-	omap4_sar_modules[L3_CLK2_INDEX] = ioremap(L3_44XX_BASE_CLK2, SZ_1M);
-	BUG_ON(!omap4_sar_modules[L3_CLK2_INDEX]);
-	omap4_sar_modules[L3_CLK3_INDEX] = ioremap(L3_44XX_BASE_CLK3, SZ_1M);
-	BUG_ON(!omap4_sar_modules[L3_CLK3_INDEX]);
-	omap4_sar_modules[USBTLL_INDEX] = ioremap(OMAP44XX_USBTLL_BASE, SZ_1M);
-	BUG_ON(!omap4_sar_modules[USBTLL_INDEX]);
-	omap4_sar_modules[UHH_INDEX] = ioremap(OMAP44XX_UHH_CONFIG_BASE, SZ_1M);
-	BUG_ON(!omap4_sar_modules[UHH_INDEX]);
-	omap4_sar_modules[L4CORE_INDEX] = ioremap(L4_44XX_PHYS, SZ_4M);
-	BUG_ON(!omap4_sar_modules[L4CORE_INDEX]);
-	omap4_sar_modules[L4PER_INDEX] = ioremap(L4_PER_44XX_PHYS, SZ_4M);
-	BUG_ON(!omap4_sar_modules[L4PER_INDEX]);
+	sar_modules = omap44xx_sar_modules;
+
+	sar_ioremap_modules();
+
+	sar_layout_generate();
 
 	/*
 	 * SAR BANK3 contains all firewall settings and it's saved through
Signature · 1 line
1.7.4.1
maintainer
#26 lore raw

PATCH 6/19 ARM: OMAP4: Auto generate SAR layout contents

Quoted 4 lines · Tero Kristo
arch/arm/mach-omap2/omap-sar.c +1 -1
-void omap4_sar_overwrite(void)
+void omap_sar_overwrite(void)
 {
 	u32 val = 0;

arch/arm/mach-omap2/omap-sar.c int omap4_sar_save(void) · line 183

Quoted 10 lines
arch/arm/mach-omap2/omap-sar.c +6 -3
-	u32 offset = 0;
+	u32 usb_offset = 0x2ec;
+	u32 usb_offset2 = 0x91c;
 
-	if (cpu_is_omap446x())
-		offset = 0x04;
+	if (cpu_is_omap446x()) {
+		usb_offset = 0x2f4;
+		usb_offset2 = 0x920;
+	}

Here too you should initialized these during __init. Otherwise we'll end up piling more and more if else cpu_is_omapxxxx for future omaps that again might change the offsets.

Tony

#27 lore raw

PATCH 7/19 ARM: OMAP4: SAR: generate overwrite data based on SAR ROM contents

In reply to Tero Kristo

omap_sar_overwrite() now uses offsets detected during init time from the SAR ROM contents.

---
 arch/arm/mach-omap2/omap-sar.c |  158 ++++++++++++++++++++++++++++------------
 1 files changed, 112 insertions(+), 46 deletions(-)
arch/arm/mach-omap2/omap-sar.c +112 -46
index da4696a..0572e7b 100644
@@ -38,7 +38,52 @@ struct sar_ram_entry {
 	u32 ram_addr;
 };
 
+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,
+	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 },
+};
+
+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 :
@@ -174,58 +219,76 @@ int omap_sar_save(void)
 void omap_sar_overwrite(void)
 {
 	u32 val = 0;
-	u32 usb_offset = 0x2ec;
-	u32 usb_offset2 = 0x91c;
+	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 (cpu_is_omap446x()) {
-		usb_offset = 0x2f4;
-		usb_offset2 = 0x920;
+	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);
 	}
 
-	/* Overwriting Phase1 data to be restored */
-	/* CM2 MEMIF_CLKTRCTRL = SW_WKUP, before FREQ UPDATE */
-	__raw_writel(0x2, sar_ram_base + SAR_BANK1_OFFSET + 0xd0);
-	/* CM1 CM_SHADOW_FREQ_CONFIG2, Enable FREQ UPDATE */
-	val = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG2);
-	/*
-	 * FIXME: Implement FREQ UPDATE for L#/M5 before enabling this
-	 * val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT;
-	 */
-	__raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + 0x100);
-	/* CM1 CM_SHADOW_FREQ_CONFIG1, Enable FREQ UPDATE */
-	val = __raw_readl(OMAP4430_CM_SHADOW_FREQ_CONFIG1);
-	val |= 1 << OMAP4430_FREQ_UPDATE_SHIFT;
-	val &= ~OMAP4430_DLL_OVERRIDE_2_2_MASK;
-	__raw_writel(val, sar_ram_base + SAR_BANK1_OFFSET + 0x104);
-	/* CM2 MEMIF_CLKTRCTRL = HW_AUTO, after FREQ UPDATE */
-	__raw_writel(0x3, sar_ram_base + SAR_BANK1_OFFSET + 0x124);
-
-	/* Overwriting Phase2a data to be restored */
-	/* CM_L3INIT_USB_HOST_CLKCTRL: SAR_MODE = 1, MODULEMODE = 2 */
-	__raw_writel(0x00000012,
-		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset);
-	/* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 1, MODULEMODE = 1 */
-	__raw_writel(0x00000011,
-		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset + 4);
-	/* CM2 CM_SDMA_STATICDEP : Enable static depedency for SAR modules */
-	__raw_writel(0x000090e8,
-		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset + 8);
-
-	/* 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 + SAR_BANK1_OFFSET + usb_offset2);
-	/* CM_L3INIT_USB_TLL_CLKCTRL: SAR_MODE = 0, MODULEMODE = 0 */
-	__raw_writel(0x0000000,
-		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset2 + 4);
-	/* CM2 CM_SDMA_STATICDEP : Clear the static depedency */
-	__raw_writel(0x00000040,
-		     sar_ram_base + SAR_BANK1_OFFSET + usb_offset2 + 8);
+	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);
+	}
 
 	/* readback to ensure data reaches to SAR RAM */
 	barrier();
-	val = __raw_readl(sar_ram_base + SAR_BANK1_OFFSET + usb_offset2 + 8);
+	val = __raw_readl(sar_ram_base + offset + 8);
 }
 
 void __iomem *omap4_get_sar_ram_base(void)
@@ -327,6 +390,8 @@ static int sar_layout_generate(void)
 				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]++;
 				}
 			}
@@ -400,6 +465,7 @@ static int __init omap4_sar_ram_init(void)
 	BUG_ON(!sar_ram_base);
 
 	sar_modules = omap44xx_sar_modules;
+	sar_overwrite_data = omap4_sar_overwrite_data;
 
 	sar_ioremap_modules();
 
Signature · 1 line
1.7.4.1
#28 lore raw

PATCH 8/19 ARM: OMAP4: PM: Add device-off support

In reply to Tero Kristo

This patch adds device off support to OMAP4 device type.

OFF mode is disabled by default, however, there are two ways to enable OFF mode:
a) In the board file, call omap4_pm_off_mode_enable(1)
b) Enable OFF mode using the debugfs entry
echo "1">/sys/kernel/debug/pm_debug/enable_off_mode (conversely echo '0' will disable it as well).

[t-kristo at ti.com: largely re-structured the code]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   24 ++++++++++-
 arch/arm/mach-omap2/omap-wakeupgen.c      |   47 +++++++++++++++++++-
 arch/arm/mach-omap2/pm-debug.c            |   17 +++++--
 arch/arm/mach-omap2/pm.h                  |   28 ++++++++++--
 arch/arm/mach-omap2/pm44xx.c              |   45 +++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.c             |   66 +++++++++++++++++++++++++++++
 6 files changed, 214 insertions(+), 13 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +22 -2
index e02c082..b9a2cc7 100644
@@ -60,6 +60,7 @@
 #include "prcm44xx.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
+#include "cm44xx.h"
 
 #ifdef CONFIG_SMP
 
@@ -232,6 +233,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;
@@ -263,9 +265,21 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
-		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
+	if (omap4_device_next_state_off()) {
+		/* Save the device context to SAR RAM */
+		ret = omap_sar_save();
+		if (ret)
+			return ret;
+		omap_sar_overwrite();
+		omap4_cm_prepare_off();
+		omap4_dpll_prepare_off();
+		save_state = 3;
+	} else if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
+		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) {
 		save_state = 2;
+	} else if (pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_OFF) {
+		save_state = 3;
+	}
 
 	cpu_clear_prev_logic_pwrst(cpu);
 	set_cpu_next_pwrst(cpu, power_state);
@@ -288,6 +302,12 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
+	if (omap4_device_prev_state_off()) {
+		omap4_dpll_resume_off();
+		omap4_cm_resume_off();
+		omap4_device_clear_prev_off_state();
+	}
+
 	pwrdm_post_transition();
 
 	return 0;
arch/arm/mach-omap2/omap-wakeupgen.c +45 -2

82 lines not on this page · raw message

arch/arm/mach-omap2/pm-debug.c +12 -5
index d9a8e42..d8cf5e5 100644
@@ -40,6 +40,7 @@
 
 u32 enable_off_mode;
 static u32 enable_oswr_mode;
+static void (*off_mode_enable_func) (int);
 
 #ifdef CONFIG_DEBUG_FS
 #include <linux/debugfs.h>
@@ -249,7 +250,8 @@ static int option_set(void *data, u64 val)
 		else
 			omap_pm_disable_off_mode();
 
-		omap3_pm_off_mode_enable(val);
+		if (off_mode_enable_func)
+			off_mode_enable_func(val);
 	}
 
 	if (option == &enable_oswr_mode)
@@ -278,16 +280,21 @@ static int __init pm_dbg_init(void)
 
 	pwrdm_for_each(pwrdms_setup, (void *)d);
 
-	if (cpu_is_omap34xx())
-		(void) debugfs_create_file("enable_off_mode",
-			S_IRUGO | S_IWUSR, d, &enable_off_mode,
-			&pm_dbg_option_fops);
+	(void) debugfs_create_file("enable_off_mode",
+		S_IRUGO | S_IWUSR, d, &enable_off_mode,
+		&pm_dbg_option_fops);
 
 	if (cpu_is_omap44xx())
 		(void) debugfs_create_file("enable_oswr_mode",
 			S_IRUGO | S_IWUSR, d, &enable_oswr_mode,
 			&pm_dbg_option_fops);
 
+	if (cpu_is_omap34xx())
+		off_mode_enable_func = omap3_pm_off_mode_enable;
+
+	if (cpu_is_omap44xx())
+		off_mode_enable_func = omap4_pm_off_mode_enable;
+
 	pm_dbg_init_done = 1;
 
 	return 0;
arch/arm/mach-omap2/pm.h +24 -4
index c13e3c1..f65da57 100644
@@ -18,6 +18,7 @@
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap4_pm_oswr_mode_enable(int);
+extern void omap4_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
@@ -26,6 +27,25 @@ extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
 extern int (*omap_pm_suspend)(void);
 extern void omap_trigger_io_chain(void);
 
+#ifdef CONFIG_PM
+extern void omap4_device_set_state_off(u8 enable);
+extern bool omap4_device_prev_state_off(void);
+extern bool omap4_device_next_state_off(void);
+extern void omap4_device_clear_prev_off_state(void);
+#else
+static inline void omap4_device_set_state_off(u8 enable)
+{
+}
+static inline bool omap4_device_prev_state_off(void)
+{
+	return false;
+}
+static inline bool omap4_device_next_state_off(void)
+{
+	return false;
+}
+#endif
+
 #if defined(CONFIG_PM_OPP)
 extern int omap3_opp_init(void);
 extern int omap4_opp_init(void);
@@ -139,13 +159,13 @@ static inline int omap4_twl_init(void)
 #endif
 
 #ifdef CONFIG_PM
-extern int omap4_sar_save(void);
-extern void omap4_sar_overwrite(void);
+extern int omap_sar_save(void);
+extern void omap_sar_overwrite(void);
 #else
-static inline void omap4_sar_save(void)
+static inline void omap_sar_save(void)
 {
 }
-static inline void omap4_sar_overwrite(void)
+static inline void omap_sar_overwrite(void)
 {
 }
 #endif
arch/arm/mach-omap2/pm44xx.c +45 -0

57 lines not on this page · raw message

arch/arm/mach-omap2/prm44xx.c +66 -0

72 lines not on this page · raw message

Signature · 1 line
1.7.4.1
#29 lore raw

PATCH 8/19 ARM: OMAP4: PM: Add device-off support

Hi Tero,

Quoted 42 lines · Tero Kristo

This patch adds device off support to OMAP4 device type.

OFF mode is disabled by default, however, there are two ways to enable OFF mode:
a) In the board file, call omap4_pm_off_mode_enable(1)
b) Enable OFF mode using the debugfs entry
echo "1">/sys/kernel/debug/pm_debug/enable_off_mode (conversely echo '0' will disable it as well).

[t-kristo at ti.com: largely re-structured the code]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   24 ++++++++++-
 arch/arm/mach-omap2/omap-wakeupgen.c      |   47 +++++++++++++++++++-
 arch/arm/mach-omap2/pm-debug.c            |   17 +++++--
 arch/arm/mach-omap2/pm.h                  |   28 ++++++++++--
 arch/arm/mach-omap2/pm44xx.c              |   45 +++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.c             |   66 +++++++++++++++++++++++++++++
 6 files changed, 214 insertions(+), 13 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +2 -0
index e02c082..b9a2cc7 100644
@@ -60,6 +60,7 @@
 #include "prcm44xx.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
+#include "cm44xx.h"
 
 #ifdef CONFIG_SMP
 
@@ -232,6 +233,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;

arch/arm/mach-omap2/omap-mpuss-lowpower.c int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) · line 272

Quoted 10 lines
arch/arm/mach-omap2/omap-mpuss-lowpower.c +5 -2
@@ -263,9 +265,21 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
-		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
+	if (omap4_device_next_state_off()) {
+		/* Save the device context to SAR RAM */
+		ret = omap_sar_save();
+		if (ret)
+			return ret;

Is it safe to simply return here? I was not sure if we need to call pwrdm_post_transition, given that we have already called pwrdm_pre_transition on entry.

Cheers
Jon

#30 lore raw

PATCH 8/19 ARM: OMAP4: PM: Add device-off support

Quoted 51 lines · Jon Hunter

Hi Tero,

Quoted 48 lines · Tero Kristo

This patch adds device off support to OMAP4 device type.

OFF mode is disabled by default, however, there are two ways to enable OFF mode:
a) In the board file, call omap4_pm_off_mode_enable(1)
b) Enable OFF mode using the debugfs entry
echo "1">/sys/kernel/debug/pm_debug/enable_off_mode (conversely echo '0' will disable it as well).

[t-kristo at ti.com: largely re-structured the code]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   24 ++++++++++-
 arch/arm/mach-omap2/omap-wakeupgen.c      |   47 +++++++++++++++++++-
 arch/arm/mach-omap2/pm-debug.c            |   17 +++++--
 arch/arm/mach-omap2/pm.h                  |   28 ++++++++++--
 arch/arm/mach-omap2/pm44xx.c              |   45 +++++++++++++++++++
 arch/arm/mach-omap2/prm44xx.c             |   66 +++++++++++++++++++++++++++++
 6 files changed, 214 insertions(+), 13 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +3 -2
index e02c082..b9a2cc7 100644
@@ -60,6 +60,7 @@
 #include "prcm44xx.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
+#include "cm44xx.h"
 
 #ifdef CONFIG_SMP
 
@@ -232,6 +233,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;
@@ -263,9 +265,21 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
-		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
+	if (omap4_device_next_state_off()) {
Quoted 8 lines

arch/arm/mach-omap2/omap-mpuss-lowpower.c int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) · line 272

Quoted 4 lines
arch/arm/mach-omap2/omap-mpuss-lowpower.c +4 -0
+		/* Save the device context to SAR RAM */
+		ret = omap_sar_save();
+		if (ret)
+			return ret;

Is it safe to simply return here? I was not sure if we need to call pwrdm_post_transition, given that we have already called pwrdm_pre_transition on entry.

Hmm, thats a good point, I'll change the patch slightly. Anyway, currently the potential solo pwrdm_pre_transition() will not break anything, but in future it would, as we are planning to control AUTO_RET feature through the pwrdm_pre / pwrdm_post calls.

-Tero

#31 lore raw

PATCH 9/19 ARM: OMAP4: PM: add errata support

In reply to Tero Kristo

Added similar PM errata flag support as omap3 has. A few errata flags will be added in subsequent patches.

---
 arch/arm/mach-omap2/pm.h     |    7 +++++++
 arch/arm/mach-omap2/pm44xx.c |    1 +
 2 files changed, 8 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/pm.h +7 -0
index f65da57..e78ec63 100644
@@ -131,6 +131,13 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
 static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #endif		/* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
 
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4)
+extern u16 pm44xx_errata;
+#define IS_PM44XX_ERRATUM(id)		(pm44xx_errata & (id))
+#else
+#define IS_PM44XX_ERRATUM(id)		0
+#endif
+
 #ifdef CONFIG_OMAP_SMARTREFLEX
 extern int omap_devinit_smartreflex(void);
 extern void omap_enable_smartreflex_on_init(void);
arch/arm/mach-omap2/pm44xx.c +1 -0
index 8f0ec56..8238097 100644
@@ -35,6 +35,7 @@ struct power_state {
 };
 
 static LIST_HEAD(pwrst_list);
+u16 pm44xx_errata;
 
 #ifdef CONFIG_SUSPEND
 static int omap4_pm_suspend(void)
Signature · 1 line
1.7.4.1
#32 lore raw

PATCH 10/19 ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA

In reply to Tero Kristo

From: Santosh Shilimkar <[email protected]>

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

[t-kristo at ti.com: added omap4 pm errata support]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   53 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.h                  |    2 +
 arch/arm/mach-omap2/pm44xx.c              |    9 +++++
 3 files changed, 64 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +53 -0
index b9a2cc7..208d4a4 100644
@@ -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;
 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.
@@ -215,6 +234,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))
+		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))
+		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
@@ -273,11 +320,14 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 		omap_sar_overwrite();
 		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	} else if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
 		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) {
+		save_ivahd_tesla_regs();
 		save_state = 2;
 	} else if (pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_OFF) {
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	}
 
@@ -302,6 +352,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
+	if (omap4_mpuss_read_prev_context_state())
+		restore_ivahd_tesla_regs();
+
 	if (omap4_device_prev_state_off()) {
 		omap4_dpll_resume_off();
 		omap4_cm_resume_off();
arch/arm/mach-omap2/pm.h +2 -0
index e78ec63..051aeb9 100644
@@ -131,6 +131,8 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
 static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #endif		/* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
 
+#define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM	(1 << 0)
+
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
 #define IS_PM44XX_ERRATUM(id)		(pm44xx_errata & (id))
arch/arm/mach-omap2/pm44xx.c +9 -0
index 8238097..67cb799 100644
@@ -263,6 +263,15 @@ static 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 (cpu_is_omap443x() && omap_type() != OMAP2_DEVICE_TYPE_GP)
+		pm44xx_errata |= PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM;
+
 #ifdef CONFIG_SUSPEND
 	omap_pm_suspend = omap4_pm_suspend;
 #endif
Signature · 1 line
1.7.4.1
#33 lore raw

PATCH 10/19 ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA

Hi Tero,

Quoted 18 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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

Quoted 5 lines

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

You may wish to state which devices is impacted by this in the changelog.

Quoted 126 lines
[t-kristo at ti.com: added omap4 pm errata support]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   53 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.h                  |    2 +
 arch/arm/mach-omap2/pm44xx.c              |    9 +++++
 3 files changed, 64 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +53 -0
index b9a2cc7..208d4a4 100644
@@ -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;
 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.
@@ -215,6 +234,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))
+		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))
+		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
@@ -273,11 +320,14 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 		omap_sar_overwrite();
 		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	} else if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
 		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) {
+		save_ivahd_tesla_regs();
 		save_state = 2;
 	} else if (pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_OFF) {
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	}
 
@@ -302,6 +352,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
+	if (omap4_mpuss_read_prev_context_state())
+		restore_ivahd_tesla_regs();
+
 	if (omap4_device_prev_state_off()) {
 		omap4_dpll_resume_off();
 		omap4_cm_resume_off();
arch/arm/mach-omap2/pm.h +2 -0
index e78ec63..051aeb9 100644
@@ -131,6 +131,8 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
 static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #endif		/* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
 
+#define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM	(1 << 0)
+
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
 #define IS_PM44XX_ERRATUM(id)		(pm44xx_errata & (id))
arch/arm/mach-omap2/pm44xx.c +0 -0
index 8238097..67cb799 100644
@@ -263,6 +263,15 @@ static int __init omap4_pm_init(void)
 

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 273

Quoted 10 lines
arch/arm/mach-omap2/pm44xx.c +8 -0
 	(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 (cpu_is_omap443x() && omap_type() != OMAP2_DEVICE_TYPE_GP)
+		pm44xx_errata |= PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM;

This erratum does not impact omap4430 es2.3 so the above should account for that.

Cheers
Jon

#34 lore raw

PATCH 10/19 ARM: OMAP4: PM: Work-around for ROM code BUG of IVAHD/TESLA

Quoted 21 lines · Jon Hunter

Hi Tero,

Quoted 18 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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

Quoted 7 lines
Quoted 5 lines

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

You may wish to state which devices is impacted by this in the changelog.

Okay.

Quoted 129 lines
Quoted 129 lines
[t-kristo at ti.com: added omap4 pm errata support]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   53 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm.h                  |    2 +
 arch/arm/mach-omap2/pm44xx.c              |    9 +++++
 3 files changed, 64 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +53 -0
index b9a2cc7..208d4a4 100644
@@ -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;
 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.
@@ -215,6 +234,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))
+		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))
+		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
@@ -273,11 +320,14 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 		omap_sar_overwrite();
 		omap4_cm_prepare_off();
 		omap4_dpll_prepare_off();
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	} else if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
 		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) {
+		save_ivahd_tesla_regs();
 		save_state = 2;
 	} else if (pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_OFF) {
+		save_ivahd_tesla_regs();
 		save_state = 3;
 	}
 
@@ -302,6 +352,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
+	if (omap4_mpuss_read_prev_context_state())
+		restore_ivahd_tesla_regs();
+
 	if (omap4_device_prev_state_off()) {
 		omap4_dpll_resume_off();
 		omap4_cm_resume_off();
arch/arm/mach-omap2/pm.h +2 -0
index e78ec63..051aeb9 100644
@@ -131,6 +131,8 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
 static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #endif		/* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
 
+#define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM	(1 << 0)
+
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
 #define IS_PM44XX_ERRATUM(id)		(pm44xx_errata & (id))
arch/arm/mach-omap2/pm44xx.c +0 -0
index 8238097..67cb799 100644
@@ -263,6 +263,15 @@ static int __init omap4_pm_init(void)
 
 	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
Quoted 11 lines

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 273

Quoted 8 lines
arch/arm/mach-omap2/pm44xx.c +8 -0
+	/*
+	 * 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 (cpu_is_omap443x() && omap_type() != OMAP2_DEVICE_TYPE_GP)
+		pm44xx_errata |= PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM;

This erratum does not impact omap4430 es2.3 so the above should account for that.

Okay, will change that.

-Tero

#35 lore raw

PATCH 11/19 ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode

In reply to Tero Kristo

From: Rajendra Nayak <[email protected]>

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.

[t-kristo at ti.com: added omap4 pm errata support]
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   35 ++++++++++++++++++++++++++++-
 arch/arm/mach-omap2/pm.h                  |    1 +
 arch/arm/mach-omap2/pm44xx.c              |    8 ++++++
 3 files changed, 43 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +34 -1
index 208d4a4..2ae5e2c 100644
@@ -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.
@@ -262,6 +268,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))
+		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))
+		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
@@ -321,13 +349,16 @@ 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_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
 		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF)) {
 		save_ivahd_tesla_regs();
+		save_l3instr_regs();
 		save_state = 2;
 	} else if (pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_OFF) {
 		save_ivahd_tesla_regs();
+		save_l3instr_regs();
 		save_state = 3;
 	}
 
@@ -352,8 +383,10 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	wakeup_cpu = smp_processor_id();
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
-	if (omap4_mpuss_read_prev_context_state())
+	if (omap4_mpuss_read_prev_context_state()) {
 		restore_ivahd_tesla_regs();
+		restore_l3instr_regs();
+	}
 
 	if (omap4_device_prev_state_off()) {
 		omap4_dpll_resume_off();
arch/arm/mach-omap2/pm.h +1 -0
index 051aeb9..c312d57 100644
@@ -132,6 +132,7 @@ static inline void enable_omap3630_toggle_l2_on_restore(void) { }
 #endif		/* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
 
 #define PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM	(1 << 0)
+#define PM_OMAP4_ROM_L3INSTR_ERRATUM		(1 << 1)
 
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4)
 extern u16 pm44xx_errata;
arch/arm/mach-omap2/pm44xx.c +8 -0
index 67cb799..0472921 100644
@@ -272,6 +272,14 @@ static int __init omap4_pm_init(void)
 	if (cpu_is_omap443x() && omap_type() != OMAP2_DEVICE_TYPE_GP)
 		pm44xx_errata |= PM_OMAP4_ROM_IVAHD_TESLA_ERRATUM;
 
+	/*
+	 * 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;
+
 #ifdef CONFIG_SUSPEND
 	omap_pm_suspend = omap4_pm_suspend;
 #endif
Signature · 1 line
1.7.4.1
#36 lore raw

PATCH 11/19 ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode

Hi Tero,

Quoted 5 lines · Tero Kristo

From: Rajendra Nayak <[email protected]>

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 appears to be an errata. So, it would be good to state explicitly here that all revisions of all omap4 devices are impacted by this errata. The code implies this but for documentation purposes it would be worth stating.

Cheers
Jon

#37 lore raw

PATCH 11/19 ARM: OMAP4: PM: save/restore CM L3INSTR registers when MPU hits OSWR/OFF mode

Quoted 5 lines · Jon Hunter

Hi Tero,

Quoted 2 lines · Tero Kristo

From: Rajendra Nayak <[email protected]>

Quoted 8 lines
Quoted 3 lines

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 appears to be an errata. So, it would be good to state explicitly here that all revisions of all omap4 devices are impacted by this errata. The code implies this but for documentation purposes it would be worth stating.

Okay, I'll add some extra beef here.

-Tero

#38 lore raw

PATCH 12/19 ARM: OMAP4: PM: update ROM return address for OSWR and OFF

In reply to Tero Kristo

From: Carlos Leija <[email protected]>

At wakeup from OFF/OSWR CPU1 will call secure HAL service through a local secure dispatcher with MMU off, 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).

[t-kristo at ti.com: merged the two patches into one]
---
 arch/arm/mach-omap2/include/mach/omap-secure.h |    1 +
 arch/arm/mach-omap2/omap-mpuss-lowpower.c      |   13 +++++++++++++
 2 files changed, 14 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/include/mach/omap-secure.h +1 -0
index c90a435..d9bde61 100644
@@ -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
 
arch/arm/mach-omap2/omap-mpuss-lowpower.c +13 -0
index 2ae5e2c..b4ca6f3 100644
@@ -52,6 +52,8 @@
 
 #include <plat/omap44xx.h>
 
+#include <mach/omap-secure.h>
+
 #include "iomap.h"
 #include "common.h"
 #include "omap4-sar-layout.h"
@@ -384,6 +386,17 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
 	if (omap4_mpuss_read_prev_context_state()) {
+		/*
+		 * 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.
+		 */
+		if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+			omap_secure_dispatcher(OMAP4_PPA_SERVICE_0,
+					       FLAG_START_CRITICAL,
+					       0, 0, 0, 0, 0);
+
 		restore_ivahd_tesla_regs();
 		restore_l3instr_regs();
 	}
Signature · 1 line
1.7.4.1
maintainer
#39 lore raw

PATCH 12/19 ARM: OMAP4: PM: update ROM return address for OSWR and OFF

Quoted 7 lines · Tero Kristo
arch/arm/mach-omap2/omap-mpuss-lowpower.c +3 -0
@@ -384,6 +386,17 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
 	if (omap4_mpuss_read_prev_context_state()) {
+		/*
+		 * Dummy dispatcher call after OSWR and OFF
+		 * Restore the right return Kernel address (with MMU on) for

arch/arm/mach-omap2/omap-mpuss-lowpower.c int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) · line 401

Quoted 10 lines
arch/arm/mach-omap2/omap-mpuss-lowpower.c +8 -0
+		 * subsequent calls to secure ROM. Otherwise the return address
+		 * will be to a PA return address and the system will hang.
+		 */
+		if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+			omap_secure_dispatcher(OMAP4_PPA_SERVICE_0,
+					       FLAG_START_CRITICAL,
+					       0, 0, 0, 0, 0);
+
 		restore_ivahd_tesla_regs();
 		restore_l3instr_regs();

This SoC test here too should be only done once during init.

Tony

#40 lore raw

PATCH 12/19 ARM: OMAP4: PM: update ROM return address for OSWR and OFF

Quoted 4 lines · Tony Lindgren
Quoted 3 lines · Tero Kristo
arch/arm/mach-omap2/omap-mpuss-lowpower.c +0 -0
@@ -384,6 +386,17 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
 
Quoted 16 lines
Quoted 4 lines
arch/arm/mach-omap2/omap-mpuss-lowpower.c +3 -0
 	if (omap4_mpuss_read_prev_context_state()) {
+		/*
+		 * Dummy dispatcher call after OSWR and OFF
+		 * Restore the right return Kernel address (with MMU on) for

arch/arm/mach-omap2/omap-mpuss-lowpower.c int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) · line 401

Quoted 10 lines
arch/arm/mach-omap2/omap-mpuss-lowpower.c +8 -0
+		 * subsequent calls to secure ROM. Otherwise the return address
+		 * will be to a PA return address and the system will hang.
+		 */
+		if (omap_type() != OMAP2_DEVICE_TYPE_GP)
+			omap_secure_dispatcher(OMAP4_PPA_SERVICE_0,
+					       FLAG_START_CRITICAL,
+					       0, 0, 0, 0, 0);
+
 		restore_ivahd_tesla_regs();
 		restore_l3instr_regs();

This SoC test here too should be only done once during init.

You sure about this one? I will end up creating a variable omap_is_gp or such, which looks somewhat silly and is going to be a duplicate (it will not provide any extra value in addition to the existing omap_type() check.) Also, similar checks are used elsewhere in the kernel, look at omap-wakeupgen.c, pm34xx.c, pm44xx.c, control.c for example. Should all of these be replaced? Well, most of these are related to secure context saving so maybe the mechanism behind these should be changed somehow globally.

-Tero

#41 lore raw

PATCH 13/19 ARM: OMAP4: PM: Mark the PPI and SPI interrupts as non-secure for GP

In reply to Tero Kristo

From: Axel Haslam <[email protected]>

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.

[t-kristo at ti.com: fixed commit message, merged multiple patches to one]
---
 arch/arm/mach-omap2/common.h           |    1 +
 arch/arm/mach-omap2/omap-wakeupgen.c   |   21 +++++++++++++++++++++
 arch/arm/mach-omap2/omap4-common.c     |    5 +++++
 arch/arm/mach-omap2/omap4-sar-layout.h |    3 +++
 4 files changed, 30 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/common.h +1 -0
index 48d1ebe..0fbb4e2 100644
@@ -200,6 +200,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);
arch/arm/mach-omap2/omap-wakeupgen.c +21 -0
index 805d08d..b2165e4 100644
@@ -41,6 +41,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;
@@ -387,6 +388,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) {
@@ -422,6 +424,25 @@ 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, ICDISR_CPU0_OFFSET, 0);
+		sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU1_OFFSET, 0);
+		for (i = 0; i < max_spi_reg; i++)
+			sar_writel(GIC_ISR_NON_SECURE, ICDISR_SPI_OFFSET, i);
+		iounmap(sar_base);
+		sar_base = NULL;
+	}
+
 	irq_hotplug_init();
 	irq_pm_init();
 
arch/arm/mach-omap2/omap4-common.c +5 -0
index 7ea4652..f6019f6 100644
@@ -112,6 +112,11 @@ void gic_dist_disable(void)
 		__raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
 }
 
+u32 gic_readl(u32 offset, u8 idx)
+{
+	return __raw_readl(gic_dist_base_addr + offset + 4 * idx);
+}
+
 #ifdef CONFIG_CACHE_L2X0
 
 void __iomem *omap4_get_l2cache_base(void)
arch/arm/mach-omap2/omap4-sar-layout.h +3 -0
index eef2839..0056667 100644
@@ -85,6 +85,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 ICDISR_CPU0_OFFSET			(SAR_BANK3_OFFSET + 0x50c)
+#define ICDISR_CPU1_OFFSET			(SAR_BANK3_OFFSET + 0x510)
+#define ICDISR_SPI_OFFSET			(SAR_BANK3_OFFSET + 0x514)
 
 /* WakeUpGen save restore offset from OMAP44XX_SAR_RAM_BASE */
 #define WAKEUPGENENB_OFFSET_CPU0		(SAR_BANK3_OFFSET + 0x684)
Signature · 1 line
1.7.4.1
#42 lore raw

PATCH 14/19 ARM: OMAP4: wakeupgen: enable clocks for save_secure_all

In reply to Tero Kristo

save_secure_all needs l3_main_3_ick and l4_secure_clkdm enabled, otherwise the secure ROM code will crash.

---
 arch/arm/mach-omap2/omap-wakeupgen.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap-wakeupgen.c +20 -0
index b2165e4..c7c4db4 100644
@@ -29,10 +29,12 @@
 
 #include <mach/omap-wakeupgen.h>
 #include <mach/omap-secure.h>
+#include <plat/omap_hwmod.h>
 
 #include "omap4-sar-layout.h"
 #include "common.h"
 #include "pm.h"
+#include "clockdomain.h"
 
 #define NR_REG_BANKS		4
 #define MAX_IRQS		128
@@ -49,6 +51,8 @@ static DEFINE_SPINLOCK(wakeupgen_lock);
 static unsigned int irq_target_cpu[NR_IRQS];
 
 static struct powerdomain *mpuss_pd;
+static struct clockdomain *l4_secure_clkdm;
+static struct omap_hwmod *l3_main_3_oh;
 
 /*
  * Static helper functions.
@@ -300,10 +304,18 @@ static void save_secure_ram(void)
 static void save_secure_all(void)
 {
 	u32 ret;
+
+	omap_hwmod_enable(l3_main_3_oh);
+	clkdm_wakeup(l4_secure_clkdm);
+
 	ret = omap_secure_dispatcher(OMAP4_HAL_SAVEALL_INDEX,
 				FLAG_START_CRITICAL,
 				1, omap_secure_ram_mempool_base(),
 				0, 0, 0);
+
+	clkdm_allow_idle(l4_secure_clkdm);
+	omap_hwmod_idle(l3_main_3_oh);
+
 	if (ret != API_HAL_RET_VALUE_OK)
 		pr_err("Secure all context save failed\n");
 }
@@ -441,6 +453,14 @@ int __init omap_wakeupgen_init(void)
 			sar_writel(GIC_ISR_NON_SECURE, ICDISR_SPI_OFFSET, i);
 		iounmap(sar_base);
 		sar_base = NULL;
+	} else {
+		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__);
+
+		l4_secure_clkdm = clkdm_lookup("l4_secure_clkdm");
+		if (!l4_secure_clkdm)
+			pr_err("%s: failed to get l4_secure_clkdm\n", __func__);
 	}
 
 	irq_hotplug_init();
Signature · 1 line
1.7.4.1
#43 lore raw

PATCH 15/19 ARM: OMAP4430: PM: workaround for DDR corruption on second CS

In reply to Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]
---
 .../include/mach/ctrl_module_wkup_44xx.h           |    2 +
 arch/arm/mach-omap2/pm44xx.c                       |   24 ++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +2 -0
index a0af9ba..b763a79 100644
@@ -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
arch/arm/mach-omap2/pm44xx.c +24 -0
index 0472921..d4d18d9 100644
@@ -17,6 +17,9 @@
 #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 "common.h"
 #include "clockdomain.h"
@@ -215,6 +218,27 @@ static 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;
+
+		secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+		BUG_ON(!secure_ctrl_mod);
+
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);
+		wmb();
+		iounmap(secure_ctrl_mod);
+	}
+
 	ret = pwrdm_for_each(pwrdms_setup, NULL);
 	if (ret) {
 		pr_err("Failed to setup powerdomains\n");
Signature · 1 line
1.7.4.1
#44 lore raw

PATCH 15/19 ARM: OMAP4430: PM: workaround for DDR corruption on second CS

Hi Tero,

Quoted 55 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]
---
 .../include/mach/ctrl_module_wkup_44xx.h           |    2 +
 arch/arm/mach-omap2/pm44xx.c                       |   24 ++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +2 -0
index a0af9ba..b763a79 100644
@@ -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
arch/arm/mach-omap2/pm44xx.c +10 -0
index 0472921..d4d18d9 100644
@@ -17,6 +17,9 @@
 #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 "common.h"
 #include "clockdomain.h"
@@ -215,6 +218,27 @@ static 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
+	 */

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 237

Quoted 10 lines
arch/arm/mach-omap2/pm44xx.c +10 -0
+	if (cpu_is_omap443x()) {
+		void __iomem *secure_ctrl_mod;
+
+		secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+		BUG_ON(!secure_ctrl_mod);
+
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);

According to the erratum description the above registers are used to restore the EMIFx_SDRAM_CONFIG2 registers. So although the value 0x10, maybe the value being used for EMIFx_SDRAM_CONFIG2 registers, shouldn't we read the EMIFx_SDRAM_CONFIG2 registers and store them in the above registers?

Cheers
Jon

#45 lore raw

PATCH 15/19 ARM: OMAP4430: PM: workaround for DDR corruption on second CS

Quoted 66 lines · Jon Hunter

Hi Tero,

Quoted 63 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]
---
 .../include/mach/ctrl_module_wkup_44xx.h           |    2 +
 arch/arm/mach-omap2/pm44xx.c                       |   24 ++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +2 -0
index a0af9ba..b763a79 100644
@@ -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
arch/arm/mach-omap2/pm44xx.c +18 -0
index 0472921..d4d18d9 100644
@@ -17,6 +17,9 @@
 #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 "common.h"
 #include "clockdomain.h"
@@ -215,6 +218,27 @@ static 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;
+
+		secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+		BUG_ON(!secure_ctrl_mod);
+
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
Quoted 8 lines

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 237

Quoted 2 lines
arch/arm/mach-omap2/pm44xx.c +2 -0
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);

According to the erratum description the above registers are used to restore the EMIFx_SDRAM_CONFIG2 registers. So although the value 0x10, maybe the value being used for EMIFx_SDRAM_CONFIG2 registers, shouldn't we read the EMIFx_SDRAM_CONFIG2 registers and store them in the above registers?

This might be a good idea, however, this patch might be tagged as TEMP until the EMIF driver is in place, this fix should rather be located there. I'll take a look at this if I can change the implementation a bit.

-Tero

#46 lore raw

PATCH 15/19 ARM: OMAP4430: PM: workaround for DDR corruption on second CS

Quoted 76 lines · Tero Kristo
Quoted 66 lines · Jon Hunter

Hi Tero,

Quoted 63 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]

---
?.../include/mach/ctrl_module_wkup_44xx.h ? ? ? ? ? | ? ?2 + ?arch/arm/mach-omap2/pm44xx.c ? ? ? ? ? ? ? ? ? ? ? | ? 24 ++++++++++++++++++++ ?2 files changed, 26 insertions(+), 0 deletions(-)

arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +0 -0
index a0af9ba..b763a79 100644
@@ -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

arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +2 -0
+#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

arch/arm/mach-omap2/pm44xx.c +0 -0
index 0472921..d4d18d9 100644
@@ -17,6 +17,9 @@

?#include <linux/err.h>
?#include <linux/slab.h>
?#include <asm/system_misc.h>

arch/arm/mach-omap2/pm44xx.c +3 -0
+#include <linux/io.h>
+
+#include <mach/ctrl_module_wkup_44xx.h>

?#include "common.h"
?#include "clockdomain.h"

arch/arm/mach-omap2/pm44xx.c +15 -0
@@ -215,6 +218,27 @@ static 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;
+
+ ? ? ? ? ? secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+ ? ? ? ? ? BUG_ON(!secure_ctrl_mod);
+
+ ? ? ? ? ? __raw_writel(0x10, secure_ctrl_mod +
+ ? ? ? ? ? ? ? ? ? ? ? ?OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
Quoted 8 lines

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 237

Quoted 2 lines
arch/arm/mach-omap2/pm44xx.c +2 -0
+ ? ? ? ? ? __raw_writel(0x10, secure_ctrl_mod +
+ ? ? ? ? ? ? ? ? ? ? ? ?OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);

According to the erratum description the above registers are used to restore the EMIFx_SDRAM_CONFIG2 registers. So although the value 0x10, maybe the value being used for EMIFx_SDRAM_CONFIG2 registers, shouldn't we read the EMIFx_SDRAM_CONFIG2 registers and store them in the above registers?

Quoted 5 lines

This might be a good idea, however, this patch might be tagged as TEMP until the EMIF driver is in place, this fix should rather be located there. I'll take a look at this if I can change the implementation a bit.

This patch doesn't have any dependency with EMIF driver since it's more of SAR restore BUG. If the dependency is from the regsister macro etc point of view, PM code can to the mapping and since it is needed only once in the init. EMIF driver is unware of SAR restore phase and that was the purpose of the DMA bases SAR restore design.

Hope this clarifies.

Regards
Santosh

#47 lore raw

PATCH 15/19 ARM: OMAP4430: PM: workaround for DDR corruption on second CS

In reply to Tero Kristo

Hi Tero,

Quoted 76 lines · Tero Kristo
Quoted 66 lines · Jon Hunter

Hi Tero,

Quoted 63 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]
---
 .../include/mach/ctrl_module_wkup_44xx.h           |    2 +
 arch/arm/mach-omap2/pm44xx.c                       |   24 ++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +2 -0
index a0af9ba..b763a79 100644
@@ -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
arch/arm/mach-omap2/pm44xx.c +18 -0
index 0472921..d4d18d9 100644
@@ -17,6 +17,9 @@
 #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 "common.h"
 #include "clockdomain.h"
@@ -215,6 +218,27 @@ static 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;
+
+		secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+		BUG_ON(!secure_ctrl_mod);
+
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
Quoted 8 lines

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 237

Quoted 2 lines
arch/arm/mach-omap2/pm44xx.c +2 -0
+		__raw_writel(0x10, secure_ctrl_mod +
+			     OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);

According to the erratum description the above registers are used to restore the EMIFx_SDRAM_CONFIG2 registers. So although the value 0x10, maybe the value being used for EMIFx_SDRAM_CONFIG2 registers, shouldn't we read the EMIFx_SDRAM_CONFIG2 registers and store them in the above registers?

Quoted 4 lines

This might be a good idea, however, this patch might be tagged as TEMP until the EMIF driver is in place, this fix should rather be located there. I'll take a look at this if I can change the implementation a bit.

By the way, I did dump the EMIF1_SDRAM_CONFIG2 register on a omap4403 and it is configured to 0x10. So I think that reading this register and saving would be safe.

Cheers
Jon

#48 lore raw

PATCH 15/19 ARM: OMAP4430: PM: workaround for DDR corruption on second CS

Quoted 79 lines · Jon Hunter

Hi Tero,

Quoted 76 lines · Tero Kristo
Quoted 74 lines · Jon Hunter

Hi Tero,

Quoted 55 lines · Tero Kristo

From: Santosh Shilimkar <[email protected]>

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.

[t-kristo at ti.com: moved workaround from omap-sar.c to pm44xx.c]

---
?.../include/mach/ctrl_module_wkup_44xx.h ? ? ? ? ? | ? ?2 + ?arch/arm/mach-omap2/pm44xx.c ? ? ? ? ? ? ? ? ? ? ? | ? 24 ++++++++++++++++++++ ?2 files changed, 26 insertions(+), 0 deletions(-)

arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +0 -0
index a0af9ba..b763a79 100644
@@ -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

arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h +2 -0
+#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

arch/arm/mach-omap2/pm44xx.c +0 -0
index 0472921..d4d18d9 100644
@@ -17,6 +17,9 @@

?#include <linux/err.h>
?#include <linux/slab.h>
?#include <asm/system_misc.h>

arch/arm/mach-omap2/pm44xx.c +3 -0
+#include <linux/io.h>
+
+#include <mach/ctrl_module_wkup_44xx.h>

?#include "common.h"
?#include "clockdomain.h"

arch/arm/mach-omap2/pm44xx.c +7 -0
@@ -215,6 +218,27 @@ static 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
+ ? ?*/

arch/arm/mach-omap2/pm44xx.c static int __init omap4_pm_init(void) · line 237

Quoted 10 lines
arch/arm/mach-omap2/pm44xx.c +10 -0
+ ? if (cpu_is_omap443x()) {
+ ? ? ? ? ? void __iomem *secure_ctrl_mod;
+
+ ? ? ? ? ? secure_ctrl_mod = ioremap(OMAP4_CTRL_MODULE_WKUP, SZ_4K);
+ ? ? ? ? ? BUG_ON(!secure_ctrl_mod);
+
+ ? ? ? ? ? __raw_writel(0x10, secure_ctrl_mod +
+ ? ? ? ? ? ? ? ? ? ? ? ?OMAP4_CTRL_SECURE_EMIF1_SDRAM_CONFIG2_REG);
+ ? ? ? ? ? __raw_writel(0x10, secure_ctrl_mod +
+ ? ? ? ? ? ? ? ? ? ? ? ?OMAP4_CTRL_SECURE_EMIF2_SDRAM_CONFIG2_REG);

According to the erratum description the above registers are used to restore the EMIFx_SDRAM_CONFIG2 registers. So although the value 0x10, maybe the value being used for EMIFx_SDRAM_CONFIG2 registers, shouldn't we read the EMIFx_SDRAM_CONFIG2 registers and store them in the above registers?

Quoted 9 lines
Quoted 4 lines

This might be a good idea, however, this patch might be tagged as TEMP until the EMIF driver is in place, this fix should rather be located there. I'll take a look at this if I can change the implementation a bit.

By the way, I did dump the EMIF1_SDRAM_CONFIG2 register on a omap4403 and it is configured to 0x10. So I think that reading this register and saving would be safe.

That's right. The reason it is harcoded is, it will be 0x10 or 0x0. Writing 0x10 even of we use 1 chip select doesn't create any issue as such.

But go ahead and read the register and store it. That way it will appear bit cleaner.

Regards
Santosh

#49 lore raw

PATCH 16/19 TEMP: ARM: OMAP4: prevent voltage transitions

In reply to Tero Kristo

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.

---
 arch/arm/mach-omap2/pm44xx.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/pm44xx.c +22 -0
index d4d18d9..e678962 100644
@@ -25,6 +25,9 @@
 #include "clockdomain.h"
 #include "powerdomain.h"
 #include "pm.h"
+#include "voltage.h"
+#include "prm44xx.h"
+#include "prm-regbits-44xx.h"
 
 struct power_state {
 	struct powerdomain *pwrdm;
@@ -207,6 +210,7 @@ static 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 (!cpu_is_omap44xx())
 		return -ENODEV;
@@ -279,6 +283,24 @@ static 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");
Signature · 1 line
1.7.4.1
#50 lore raw

PATCH 17/19 ARM: OMAP4: put cpu1 back to sleep if no wake request

In reply to Tero Kristo

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.

---
 arch/arm/mach-omap2/omap-headsmp.S |   45 ++++++++++++++++++++++++++++++++---
 1 files changed, 41 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/omap-headsmp.S +41 -4
index d602555..59c6578 100644
@@ -17,8 +17,37 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <mach/omap-secure.h>
+#include "prcm_mpu44xx.h"
+
+#define CPU1_PWRSTCTRL (OMAP4430_PRCM_MPU_BASE + OMAP4430_PRCM_MPU_CPU1_INST + \
+			OMAP4_PM_CPU1_PWRSTCTRL_OFFSET)
 
 	__CPUINIT
+
+ENTRY(omap_cpu1_off)
+	ldr	r12, =CPU1_PWRSTCTRL
+	ldr	r0, [r12]
+	and	r0, #3
+	cmp	r0, #2
+	beq	exit_cpu1_off
+
+	mov	r0, #0x3
+	mov	r1, #0x0
+	ldr	r12, =OMAP4_MON_SCU_PWR_INDEX
+	dsb
+	smc     #0
+
+	isb
+	dsb
+	dmb
+	wfi
+	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
@@ -27,32 +56,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
Signature · 1 line
1.7.4.1
#51 lore raw

PATCH 18/19 ARM: OMAP4460: wakeupgen: set GIC_CPU0 backup status flag always

In reply to Tero Kristo

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.

---
 arch/arm/mach-omap2/omap-wakeupgen.c   |   14 ++++++++++++++
 arch/arm/mach-omap2/omap4-sar-layout.h |    1 +
 2 files changed, 15 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap-wakeupgen.c +14 -0
index c7c4db4..30da299 100644
@@ -447,10 +447,24 @@ int __init omap_wakeupgen_init(void)
 
 	if (omap_type() == OMAP2_DEVICE_TYPE_GP) {
 		sar_base = ioremap(OMAP44XX_SAR_RAM_BASE, SZ_16K);
+		/* Clean GIC SAR area */
+		for (i = SAR_BACKUP_STATUS_OFFSET; i < WAKEUPGENENB_OFFSET_CPU0;
+			i += 4)
+			sar_writel(0, i, 0);
+
 		sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU0_OFFSET, 0);
 		sar_writel(GIC_ISR_NON_SECURE, ICDISR_CPU1_OFFSET, 0);
 		for (i = 0; i < max_spi_reg; i++)
 			sar_writel(GIC_ISR_NON_SECURE, ICDISR_SPI_OFFSET, i);
+
+		/*
+		 * Set CPU0 GIC backup flag permanently for omap4460,
+		 * this is needed because of the ROM code bug that breaks
+		 * GIC during wakeup from device off
+		 */
+		if (cpu_is_omap446x())
+			__raw_writel(SAR_BACKUP_STATUS_GIC_CPU0,
+				     sar_base + SAR_BACKUP_STATUS_OFFSET);
 		iounmap(sar_base);
 		sar_base = NULL;
 	} else {
arch/arm/mach-omap2/omap4-sar-layout.h +1 -0
index 0056667..e621c51 100644
@@ -88,6 +88,7 @@
 #define ICDISR_CPU0_OFFSET			(SAR_BANK3_OFFSET + 0x50c)
 #define ICDISR_CPU1_OFFSET			(SAR_BANK3_OFFSET + 0x510)
 #define 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)
Signature · 1 line
1.7.4.1
#52 lore raw

PATCH 19/19 ARM: OMAP4: powerdomain: update mpu / core off counters during device off

In reply to Tero Kristo

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 RETENTION 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_post_transition to see if a device off type context loss has happened. If this is the case, the counters + timers for OFF state are touched instead of RETENTION.

---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c   |    1 -
 arch/arm/mach-omap2/powerdomain.c           |    9 +++++++++
 arch/arm/mach-omap2/powerdomain.h           |    2 ++
 arch/arm/mach-omap2/powerdomains44xx_data.c |    2 ++
 arch/arm/mach-omap2/prm44xx.c               |   15 +++++++++++++++
 arch/arm/mach-omap2/prm44xx.h               |    2 ++
 6 files changed, 30 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/omap-mpuss-lowpower.c +0 -1
index b4ca6f3..b7d139a 100644
@@ -404,7 +404,6 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	if (omap4_device_prev_state_off()) {
 		omap4_dpll_resume_off();
 		omap4_cm_resume_off();
-		omap4_device_clear_prev_off_state();
 	}
 
 	pwrdm_post_transition();
arch/arm/mach-omap2/powerdomain.c +9 -0
index 068f06b..cb3eab2 100644
@@ -160,6 +160,15 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 		break;
 	case PWRDM_STATE_PREV:
 		prev = pwrdm_read_prev_pwrst(pwrdm);
+
+		/*
+		 * If powerdomain has context offset defined, check if
+		 * the domain has lost context (i.e. entered off)
+		 */
+		if (pwrdm->context_offs)
+			if (omap4_pwrdm_lost_context_rff(pwrdm->prcm_offs,
+							 pwrdm->context_offs))
+				prev = PWRDM_POWER_OFF;
 		if (pwrdm->state != prev)
 			pwrdm->state_counter[prev]++;
 		if (prev == PWRDM_POWER_RET)
arch/arm/mach-omap2/powerdomain.h +2 -0
index 0d72a8a..a427645 100644
@@ -82,6 +82,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
@@ -106,6 +107,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;
arch/arm/mach-omap2/powerdomains44xx_data.c +2 -0
index d8701ce..c4de02f 100644
@@ -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,
arch/arm/mach-omap2/prm44xx.c +15 -0
index ab810cd..cf996a6 100644
@@ -274,6 +274,21 @@ static void __init omap4_enable_io_wakeup(void)
 			OMAP4_PRM_IO_PMCTRL_OFFSET);
 }
 
+bool omap4_pwrdm_lost_context_rff(s16 inst, s16 offset)
+{
+	u32 val;
+
+	val = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, inst, offset);
+
+	if (val & OMAP4430_LOSTCONTEXT_RFF_MASK) {
+		omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION, inst,
+					     offset);
+		return true;
+	}
+
+	return false;
+}
+
 /**
  * omap4_device_set_state_off() - setup device off state
  * @enable:	set to off or not.
arch/arm/mach-omap2/prm44xx.h +2 -0
index 54a057e..517851b 100644
@@ -770,6 +770,8 @@ extern void omap44xx_prm_ocp_barrier(void);
 extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
 extern void omap44xx_prm_restore_irqen(u32 *saved_mask);
 
+extern bool omap4_pwrdm_lost_context_rff(s16 inst, s16 offset);
+
 # endif
 
 #endif
Signature · 1 line
1.7.4.1
#53 lore raw

cover ARM: OMAP4 device off support

In reply to Tero Kristo
Quoted 9 lines · Tero Kristo

Hi,

First version for this work. Applies on top of mainline + iochain set + OMAP4 core retention set. Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.4-omap4-dev-off

Tested on omap4430 EMU blaze + omap4460 GP panda boards.

Quoted 8 lines

Some drivers have issues with device off, most notably MMC, as it breaks device off on blaze device after 1 entry to device off mode:

[ ?208.906921] omap_i2c omap_i2c.1: XRDY IRQ while no data to send [ ?209.905639] omap_i2c omap_i2c.1: controller timed out
[ ?209.905792] twl: i2c_read failed to transfer all messages
[ ?209.905792] omap_hsmmc omap_hsmmc.1: could not set regulator OCR (-110) [ ?212.296203] mmc0: error -110 during resume (card was removed?)

Hi Tero,

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Quoted 15 lines

[ ?212.562164] PM: resume of devices complete after 3656.007 msecs [ ?212.660125] Restarting tasks ... done.
#

# echo mem > /sys/power/state
[ ?220.376892] PM: Syncing filesystems ... done.
[ ?220.382476] Freezing user space processes ... (elapsed 0.01 seconds) done.
[ ?220.408386] Freezing remaining freezable tasks ... (elapsed 0.02 seconds) don
e.
[ ?220.439605] Suspending console(s) (use no_console_suspend to debug)
[ ?220.454650] dpm_run_callback(): platform_pm_suspend+0x0/0x54 returns -110
[ ?220.454711] PM: Device omap_hsmmc.1 failed to suspend: error -110
[ ?220.454711] PM: Some devices failed to suspend
[ ?220.718261] PM: resume of devices complete after 263.539 msecs
[ ?220.743988] Restarting tasks ... done.
Quoted 5 lines

Attempting to disable MMC from config prevented boot completely for me, so this issue is likely to stay until someone fixes the MMC driver. Panda device works fine though, although the wakeup from device off is slow due to problems with some other drivers (most likely I2C.)

can you try this patch if you want to disable MMC
http://permalink.gmane.org/gmane.linux.ports.arm.omap/74540
or
http://www.spinics.net/lists/linux-omap/msg67879.html
and build omap_hsmmc as module.

Quoted 17 lines

Off mode is disabled by default, it can be enabled by either calling omap4_pm_enable_off_mode(1) from board files or alternatively writing to a debugfs node from userspace:

echo 1 > /debug/pm_debug/enable_off_mode

Device off entry can be tracked through the debugfs also, it increases the core_pwrdm OFF state counter / timer, as this is an invalid state for the chip normally (core enters OSWR in device off.) Not sure if this a good way to do this but comments are welcome.

-Tero

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

#54 lore raw

cover ARM: OMAP4 device off support

Quoted 18 lines · Balaji
Quoted 9 lines · Tero Kristo

Hi,

First version for this work. Applies on top of mainline + iochain set + OMAP4 core retention set. Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.4-omap4-dev-off

Tested on omap4430 EMU blaze + omap4460 GP panda boards.

Quoted 8 lines

Some drivers have issues with device off, most notably MMC, as it breaks device off on blaze device after 1 entry to device off mode:

[  208.906921] omap_i2c omap_i2c.1: XRDY IRQ while no data to send
[  209.905639] omap_i2c omap_i2c.1: controller timed out
[  209.905792] twl: i2c_read failed to transfer all messages
[  209.905792] omap_hsmmc omap_hsmmc.1: could not set regulator OCR (-110)
[  212.296203] mmc0: error -110 during resume (card was removed?)
Quoted 7 lines

Hi Tero,

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Did you try this with off-mode enabled and did you check the device actually goes to off? (see pm_debug/count and verify core off count is increasing.) And as said, I was only able to see this problem on a blaze device, panda works fine. But yes, you are probably right and it is not an MMC driver issue but I2C.

Quoted 16 lines
Quoted 16 lines
[  212.562164] PM: resume of devices complete after 3656.007 msecs
[  212.660125] Restarting tasks ... done.
#
# echo mem > /sys/power/state
[  220.376892] PM: Syncing filesystems ... done.
[  220.382476] Freezing user space processes ... (elapsed 0.01 seconds) done.
[  220.408386] Freezing remaining freezable tasks ... (elapsed 0.02 seconds) don
e.
[  220.439605] Suspending console(s) (use no_console_suspend to debug)
[  220.454650] dpm_run_callback(): platform_pm_suspend+0x0/0x54 returns -110
[  220.454711] PM: Device omap_hsmmc.1 failed to suspend: error -110
[  220.454711] PM: Some devices failed to suspend
[  220.718261] PM: resume of devices complete after 263.539 msecs
[  220.743988] Restarting tasks ... done.
Quoted 8 lines
Quoted 5 lines

Attempting to disable MMC from config prevented boot completely for me, so this issue is likely to stay until someone fixes the MMC driver. Panda device works fine though, although the wakeup from device off is slow due to problems with some other drivers (most likely I2C.)

can you try this patch if you want to disable MMC
http://permalink.gmane.org/gmane.linux.ports.arm.omap/74540

Tried this patch and disabled MMC completely. Device off now works with blaze board also multiple times.

-Tero

Quoted 21 lines

or
http://www.spinics.net/lists/linux-omap/msg67879.html
and build omap_hsmmc as module.

Quoted 17 lines

Off mode is disabled by default, it can be enabled by either calling omap4_pm_enable_off_mode(1) from board files or alternatively writing to a debugfs node from userspace:

echo 1 > /debug/pm_debug/enable_off_mode

Device off entry can be tracked through the debugfs also, it increases the core_pwrdm OFF state counter / timer, as this is an invalid state for the chip normally (core enters OSWR in device off.) Not sure if this a good way to do this but comments are welcome.

-Tero

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

#55 lore raw

cover ARM: OMAP4 device off support

Tero Kristo <[email protected]> writes:

[...]

Quoted 11 lines
Quoted 5 lines

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Did you try this with off-mode enabled and did you check the device actually goes to off? (see pm_debug/count and verify core off count is increasing.) And as said, I was only able to see this problem on a blaze device, panda works fine. But yes, you are probably right and it is not an MMC driver issue but I2C.

Can you try the patch below? It sounds like the same problem.

Kevin

Quoted 1 line

From 999f34629140f436099050eb7aac514bfd2a2235 Mon Sep 17 00:00:00 2001

From: NeilBrown <[email protected]>
Date: Fri, 30 Dec 2011 12:40:30 +1100
Subject: [PATCH] OMAP/I2C - Fix timeout problem during suspend.

On a board with OMAP3 processor and TWL4030 Power management, we need to talk to the TWL4030 during late suspend but cannot because the I2C interrupt is disabled (as late suspend disables interrupt).

e.g. I get messages like:

[   62.161102] musb-omap2430 musb-omap2430: LATE power domain suspend
[   63.167205] omap_i2c omap_i2c.1: controller timed out
[   63.183044] twl: i2c_read failed to transfer all messages
[   64.182861] omap_i2c omap_i2c.1: controller timed out
[   64.198455] twl: i2c_write failed to transfer all messages
[   65.198455] omap_i2c omap_i2c.1: controller timed out
[   65.203765] twl: i2c_write failed to transfer all messages

The stack shows omap2430_runtime_suspend calling twl4030_set_suspend which tries to power-down the USB PHY (twl4030_phy_suspend -> twl4030_phy_power -> __twl4030_phy_power which as a nice WARN_ON that helps).

Then we get the same in resume:

[   69.603912] musb-omap2430 musb-omap2430: EARLY power domain resume
[   70.610473] omap_i2c omap_i2c.1: controller timed out
[   70.626129] twl: i2c_write failed to transfer all messages

etc.

So don't disable interrupts for I2C.

---
 drivers/i2c/busses/i2c-omap.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-omap.c +1 -1
index 801df60..e024c50 100644
@@ -1092,7 +1092,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
 								   omap_i2c_isr;
-	r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+	r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
 
 	if (r) {
 		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
Signature · 1 line
1.7.9.2
#56 lore raw

cover ARM: OMAP4 device off support

Quoted 10 lines · Kevin Hilman

Tero Kristo <[email protected]> writes:

[...]

Quoted 6 lines
Quoted 5 lines

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Quoted 7 lines
Quoted 5 lines

Did you try this with off-mode enabled and did you check the device actually goes to off? (see pm_debug/count and verify core off count is increasing.) And as said, I was only able to see this problem on a blaze device, panda works fine. But yes, you are probably right and it is not an MMC driver issue but I2C.

Can you try the patch below? It sounds like the same problem.

Doesn't help with this one. I guess I2C loses context during device off and it is not restored properly.

-Tero

Quoted 56 lines

Kevin

From 999f34629140f436099050eb7aac514bfd2a2235 Mon Sep 17 00:00:00 2001
From: NeilBrown <[email protected]>
Date: Fri, 30 Dec 2011 12:40:30 +1100
Subject: [PATCH] OMAP/I2C - Fix timeout problem during suspend.

On a board with OMAP3 processor and TWL4030 Power management, we need to talk to the TWL4030 during late suspend but cannot because the I2C interrupt is disabled (as late suspend disables interrupt).

e.g. I get messages like:

[   62.161102] musb-omap2430 musb-omap2430: LATE power domain suspend
[   63.167205] omap_i2c omap_i2c.1: controller timed out
[   63.183044] twl: i2c_read failed to transfer all messages
[   64.182861] omap_i2c omap_i2c.1: controller timed out
[   64.198455] twl: i2c_write failed to transfer all messages
[   65.198455] omap_i2c omap_i2c.1: controller timed out
[   65.203765] twl: i2c_write failed to transfer all messages

The stack shows omap2430_runtime_suspend calling twl4030_set_suspend which tries to power-down the USB PHY (twl4030_phy_suspend -> twl4030_phy_power -> __twl4030_phy_power which as a nice WARN_ON that helps).

Then we get the same in resume:

[   69.603912] musb-omap2430 musb-omap2430: EARLY power domain resume
[   70.610473] omap_i2c omap_i2c.1: controller timed out
[   70.626129] twl: i2c_write failed to transfer all messages

etc.

So don't disable interrupts for I2C.

---
 drivers/i2c/busses/i2c-omap.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-omap.c +1 -1
index 801df60..e024c50 100644
@@ -1092,7 +1092,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
 	isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
 								   omap_i2c_isr;
-	r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+	r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev);
 
 	if (r) {
 		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
#57 lore raw

cover ARM: OMAP4 device off support

Quoted 17 lines · Tero Kristo
Quoted 16 lines · Kevin Hilman

Tero Kristo <[email protected]> writes:

[...]

Quoted 11 lines
Quoted 5 lines

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Did you try this with off-mode enabled and did you check the device actually goes to off? (see pm_debug/count and verify core off count is increasing.) And as said, I was only able to see this problem on a blaze device, panda works fine. But yes, you are probably right and it is not an MMC driver issue but I2C.

Quoted 6 lines
Quoted 1 line

Can you try the patch below? ?It sounds like the same problem.

Doesn't help with this one. I guess I2C loses context during device off and it is not restored properly.

-Tero

Could you try the following patch

https://lkml.org/lkml/2012/3/30/345

#58 lore raw

cover ARM: OMAP4 device off support

Quoted 20 lines · Shubhrajyoti
Quoted 19 lines · Tero Kristo
Quoted 17 lines · Kevin Hilman

Tero Kristo <[email protected]> writes:

[...]

Quoted 11 lines
Quoted 5 lines

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Did you try this with off-mode enabled and did you check the device actually goes to off? (see pm_debug/count and verify core off count is increasing.) And as said, I was only able to see this problem on a blaze device, panda works fine. But yes, you are probably right and it is not an MMC driver issue but I2C.

Can you try the patch below? It sounds like the same problem.

Quoted 7 lines
Quoted 4 lines

Doesn't help with this one. I guess I2C loses context during device off and it is not restored properly.

-Tero

Could you try the following patch

https://lkml.org/lkml/2012/3/30/345

That does the trick, after this it is working fine on blaze, and this also fixes the timeout issues seen on panda board (meaning wake-up from device off is much faster.)

-Tero

#59 lore raw

cover ARM: OMAP4 device off support

Quoted 24 lines · Tero Kristo
Quoted 23 lines · Shubhrajyoti
Quoted 22 lines · Tero Kristo
Quoted 10 lines · Kevin Hilman

Tero Kristo <[email protected]> writes:

[...]

Quoted 6 lines
Quoted 5 lines

I tried your branch on gp/emu devices but could not reproduce this issue. My observation is that while resuming, omap_hsmmc.1 eMMC is trying to turn on phoenix vaux1 regulator via i2c which fails due to controller timeout.
Note: eMMC is present only on sdp/blaze

Quoted 7 lines
Quoted 5 lines

Did you try this with off-mode enabled and did you check the device actually goes to off? (see pm_debug/count and verify core off count is increasing.) And as said, I was only able to see this problem on a blaze device, panda works fine. But yes, you are probably right and it is not an MMC driver issue but I2C.

Can you try the patch below? ?It sounds like the same problem.

Doesn't help with this one. I guess I2C loses context during device off and it is not restored properly.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

-Tero

Could you try the following patch

https://lkml.org/lkml/2012/3/30/345

That does the trick, after this it is working fine on blaze, and this also fixes the timeout issues seen on panda board (meaning wake-up from device off is much faster.)

Thats great.
Feel free to try the following.
I2C conditional restore"
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg66859.html

Also cooked a below rfc/untested patch for mmc restore.

Quoted 1 line

From c28ec76f8a20c3ce59b72245ab9f3bc293b1ac43 Mon Sep 17 00:00:00 2001

From: Shubhrajyoti D <[email protected]>
Date: Mon, 23 Apr 2012 11:52:54 +0530
Subject: [RFC PATCH] hsmmc: omap: Support for device off

Attempt to have device off support. Current the function hsmmc_get_context_loss is made NULL for OMAP4. Remove it as post Terro's patches context may be lost. Also it is good to have no assumptions of the context loss in the driver.

---
 arch/arm/mach-omap2/hsmmc.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)
arch/arm/mach-omap2/hsmmc.c +0 -6
index b0268ea..2361f24 100644
@@ -32,17 +32,11 @@ static u16 control_mmc1;
 
 #define HSMMC_NAME_LEN 9
 
-#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
-
 static int hsmmc_get_context_loss(struct device *dev)
 {
        return omap_pm_get_dev_context_loss_count(dev);
 }
 
-#else
-#define hsmmc_get_context_loss NULL
-#endif
-
 static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
                                  int power_on, int vdd)
 {

--
1.7.0.4

#60 lore raw

cover ARM: OMAP4 device off support

In reply to Tero Kristo
Quoted 6 lines · Tero Kristo

Hi,

First version for this work. Applies on top of mainline + iochain set + OMAP4 core retention set. Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.4-omap4-dev-off

FYI... seems your get repo is corrupted. I tried fetching both with git and https protocols:

$ git remote add tero git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
$ git fetch tero
fatal: The remote end hung up unexpectedly
fatal: protocol error: bad pack heade
$ git remote rm tero
$ git remote add tero https://git.gitorious.org/~kristo/omap-pm/omap-pm-work.git
$ git fetch tero
error: Unable to find 653621e4dd02d4a2117e1b813d9c5f1ccb11c9ed under https://git.gitorious.org/~kristo/omap-pm/omap-pm-work.git
Cannot obtain needed object 653621e4dd02d4a2117e1b813d9c5f1ccb11c9ed
error: Fetch failed.

Kevin

#61 lore raw

cover ARM: OMAP4 device off support

Quoted 12 lines · Kevin Hilman
Quoted 6 lines · Tero Kristo

Hi,

First version for this work. Applies on top of mainline + iochain set + OMAP4 core retention set. Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.4-omap4-dev-off

FYI... seems your get repo is corrupted. I tried fetching both with git and https protocols:

Quoted 10 lines
$ git remote add tero git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
$ git fetch tero
fatal: The remote end hung up unexpectedly
fatal: protocol error: bad pack heade
$ git remote rm tero
$ git remote add tero https://git.gitorious.org/~kristo/omap-pm/omap-pm-work.git
$ git fetch tero
error: Unable to find 653621e4dd02d4a2117e1b813d9c5f1ccb11c9ed under https://git.gitorious.org/~kristo/omap-pm/omap-pm-work.git
Cannot obtain needed object 653621e4dd02d4a2117e1b813d9c5f1ccb11c9ed
error: Fetch failed.

You will have a partially transferred pack file in your repository...

#62 lore raw

cover ARM: OMAP4 device off support

Quoted 24 lines · Russell King - ARM Linux
Quoted 12 lines · Kevin Hilman
Quoted 6 lines · Tero Kristo

Hi,

First version for this work. Applies on top of mainline + iochain set + OMAP4 core retention set. Working tree available here:
tree: git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
branch: mainline-3.4-omap4-dev-off

FYI... seems your get repo is corrupted. I tried fetching both with git and https protocols:

Quoted 10 lines
$ git remote add tero git://gitorious.org/~kristo/omap-pm/omap-pm-work.git
$ git fetch tero
fatal: The remote end hung up unexpectedly
fatal: protocol error: bad pack heade
$ git remote rm tero
$ git remote add tero https://git.gitorious.org/~kristo/omap-pm/omap-pm-work.git
$ git fetch tero
error: Unable to find 653621e4dd02d4a2117e1b813d9c5f1ccb11c9ed under https://git.gitorious.org/~kristo/omap-pm/omap-pm-work.git
Cannot obtain needed object 653621e4dd02d4a2117e1b813d9c5f1ccb11c9ed
error: Fetch failed.
Quoted 1 line

You will have a partially transferred pack file in your repository...

Strange, well I pushed 1 new branch and it looks like it is cloning properly now.

-Tero