All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle
@ 2012-10-23 15:22 Shawn Guo
  2012-10-23 15:22 ` [PATCH 01/10] ARM: imx6q: print silicon version on boot Shawn Guo
                   ` (9 more replies)
  0 siblings, 10 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

The imx6q has a low power mode named WAIT.  When all cores are in WFI,
imx6q will go into WAIT mode, and whenever there is a wakeup interrupt,
it will exit WAIT mode.  Software can configure hardware behavior during
WAIT mode, clock gating or power gating for ARM core.

The series implements ARM clock gating and power gating in WAIT mode
as two coupled cpuidle states, wait and srpg.  Though imx6q hardware
already handles sequencing, the voting provided by coupled cpuidle is
still quite useful, which will allow the system to at least get into
clock gating when one cpu wants clock gating and the other wants power
gating.

Patches 1 ~ 9 make necessary code changes to prepare for WAIT mode
enabling, and the last patch enables the feature eventually.

As WAIT mode is broken on TO1.0 silicon, the feature is only provided
for revisions later than TO1.0.

Shawn Guo (10):
  ARM: imx6q: print silicon version on boot
  ARM: imx: allow timer counter to roll over
  ARM: imx6q: select ARM and PL310 errata
  ARM: imx: initialize cpu power up counters
  ARM: imx: mask gpc interrupts initially
  ARM: imx6q: prepare imx6q_set_lpm for cpudile support
  ARM: imx6q: get v7_cpu_resume ready for cpuidle
  ARM: imx: move imx6q_cpuidle_driver into a separate file
  ARM: SMP: add function arch_send_wakeup_ipi_mask()
  ARM: imx6q: implement WAIT mode with coupled cpuidle

 arch/arm/include/asm/smp.h        |    1 +
 arch/arm/kernel/smp.c             |    5 ++
 arch/arm/mach-imx/Kconfig         |    9 ++
 arch/arm/mach-imx/Makefile        |    6 +-
 arch/arm/mach-imx/clk-imx6q.c     |   32 +++++--
 arch/arm/mach-imx/common.h        |    6 +-
 arch/arm/mach-imx/cpuidle-imx6q.c |  177 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/cpuidle.c       |    3 +
 arch/arm/mach-imx/cpuidle.h       |    5 ++
 arch/arm/mach-imx/gpc.c           |   20 +++--
 arch/arm/mach-imx/headsmp.S       |   81 ++++++++++++++++-
 arch/arm/mach-imx/mach-imx6q.c    |   45 +++++++---
 arch/arm/mach-imx/platsmp.c       |   26 ++++--
 arch/arm/mach-imx/pm-imx6q.c      |    1 -
 arch/arm/mach-imx/time.c          |    6 +-
 15 files changed, 384 insertions(+), 39 deletions(-)
 create mode 100644 arch/arm/mach-imx/cpuidle-imx6q.c

-- 
1.7.9.5

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

* [PATCH 01/10] ARM: imx6q: print silicon version on boot
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-11-15 18:09   ` Moseley, Drew
  2012-10-23 15:22 ` [PATCH 02/10] ARM: imx: allow timer counter to roll over Shawn Guo
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

i.MX6Q has 3 revisions 1.0, 1.1 and 1.2.  Print revision on boot.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/mach-imx6q.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 978b6dd..1c5acf8 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -38,6 +38,33 @@
 #include "cpuidle.h"
 #include "hardware.h"
 
+#define IMX6Q_ANALOG_DIGPROG	0x260
+
+static int imx6q_revision(void)
+{
+	struct device_node *np;
+	void __iomem *base;
+	static u32 rev;
+
+	if (!rev) {
+		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
+		base = of_iomap(np, 0);
+		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG);
+		iounmap(base);
+	}
+
+	switch (rev & 0xff) {
+	case 0:
+		return IMX_CHIP_REVISION_1_0;
+	case 1:
+		return IMX_CHIP_REVISION_1_1;
+	case 2:
+		return IMX_CHIP_REVISION_1_2;
+	default:
+		return IMX_CHIP_REVISION_UNKNOWN;
+	}
+}
+
 void imx6q_restart(char mode, const char *cmd)
 {
 	struct device_node *np;
@@ -192,6 +219,7 @@ static void __init imx6q_timer_init(void)
 {
 	mx6q_clocks_init();
 	twd_local_timer_of_register();
+	imx_print_silicon_rev("i.MX6Q", imx6q_revision());
 }
 
 static struct sys_timer imx6q_timer = {
-- 
1.7.9.5

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

* [PATCH 02/10] ARM: imx: allow timer counter to roll over
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
  2012-10-23 15:22 ` [PATCH 01/10] ARM: imx6q: print silicon version on boot Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata Shawn Guo
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

The timer is configured in free-run mode.  The counter should be
allowed to roll over to 0 when reaching 0xffffffff.  Let's do that
by always returning 0 in set_next_event.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/time.c |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index f017302..858098c 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -139,8 +139,7 @@ static int mx1_2_set_next_event(unsigned long evt,
 
 	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
 
-	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
-				-ETIME : 0;
+	return 0;
 }
 
 static int v2_set_next_event(unsigned long evt,
@@ -152,8 +151,7 @@ static int v2_set_next_event(unsigned long evt,
 
 	__raw_writel(tcmp, timer_base + V2_TCMP);
 
-	return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
-				-ETIME : 0;
+	return 0;
 }
 
 #ifdef DEBUG
-- 
1.7.9.5

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

* [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
  2012-10-23 15:22 ` [PATCH 01/10] ARM: imx6q: print silicon version on boot Shawn Guo
  2012-10-23 15:22 ` [PATCH 02/10] ARM: imx: allow timer counter to roll over Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2013-11-28 12:44   ` Dirk Behme
  2012-10-23 15:22 ` [PATCH 04/10] ARM: imx: initialize cpu power up counters Shawn Guo
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

ARM core r2p10 and PL310 r3p2 are integrated on imx6q.  Select
corresponding errata.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Kconfig |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4f73866..3ce2771 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -832,6 +832,11 @@ config SOC_IMX6Q
 	select ARCH_HAS_CPUFREQ
 	select ARCH_HAS_OPP
 	select ARM_CPU_SUSPEND if PM
+	select ARM_ERRATA_743622
+	select ARM_ERRATA_751472
+	select ARM_ERRATA_754322
+	select ARM_ERRATA_764369 if SMP
+	select ARM_ERRATA_775420
 	select ARM_GIC
 	select COMMON_CLK
 	select CPU_V7
@@ -843,6 +848,9 @@ config SOC_IMX6Q
 	select MFD_SYSCON
 	select PINCTRL
 	select PINCTRL_IMX6Q
+	select PL310_ERRATA_588369 if CACHE_PL310
+	select PL310_ERRATA_727915 if CACHE_PL310
+	select PL310_ERRATA_769419 if CACHE_PL310
 	select PM_OPP if PM
 
 	help
-- 
1.7.9.5

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

* [PATCH 04/10] ARM: imx: initialize cpu power up counters
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (2 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 05/10] ARM: imx: mask gpc interrupts initially Shawn Guo
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

The default values of cpu power up counters are unnecessarily large.
Initialize them to small ones for minimizing the power up latency.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/gpc.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index e1537f9..c75842d 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -19,6 +19,7 @@
 
 #define GPC_IMR1		0x008
 #define GPC_PGC_CPU_PDN		0x2a0
+#define GPC_PGC_CPU_PUPSCR	0x2a4
 
 #define IMR_NUM			4
 
@@ -106,6 +107,9 @@ void __init imx_gpc_init(void)
 	gpc_base = of_iomap(np, 0);
 	WARN_ON(!gpc_base);
 
+	/* Initialize cpu power up counters to minimize the latency */
+	writel_relaxed(0x101, gpc_base + GPC_PGC_CPU_PUPSCR);
+
 	/* Register GPC as the secondary interrupt controller behind GIC */
 	gic_arch_extn.irq_mask = imx_gpc_irq_mask;
 	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
-- 
1.7.9.5

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

* [PATCH 05/10] ARM: imx: mask gpc interrupts initially
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (3 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 04/10] ARM: imx: initialize cpu power up counters Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 06/10] ARM: imx6q: prepare imx6q_set_lpm for cpudile support Shawn Guo
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

Mask gpc interrupts initially to avoid suspicious interrupts.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/gpc.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index c75842d..be9a6cb 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -102,6 +102,7 @@ static void imx_gpc_irq_mask(struct irq_data *d)
 void __init imx_gpc_init(void)
 {
 	struct device_node *np;
+	int i;
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
 	gpc_base = of_iomap(np, 0);
@@ -110,6 +111,10 @@ void __init imx_gpc_init(void)
 	/* Initialize cpu power up counters to minimize the latency */
 	writel_relaxed(0x101, gpc_base + GPC_PGC_CPU_PUPSCR);
 
+	/* Initially mask all interrupts */
+	for (i = 0; i < IMR_NUM; i++)
+		writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
+
 	/* Register GPC as the secondary interrupt controller behind GIC */
 	gic_arch_extn.irq_mask = imx_gpc_irq_mask;
 	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
-- 
1.7.9.5

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

* [PATCH 06/10] ARM: imx6q: prepare imx6q_set_lpm for cpudile support
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (4 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 05/10] ARM: imx: mask gpc interrupts initially Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 07/10] ARM: imx6q: get v7_cpu_resume ready for cpuidle Shawn Guo
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

WAIT_UNCLOCKED and WAIT_UNCLOCKED_POWER_OFF will be used to implement
cpuidle.  Get function imx6q_set_lpm for that.  The unused mode
STOP_POWER_ON is removed from there.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/clk-imx6q.c |   32 +++++++++++++++++++++++++++-----
 arch/arm/mach-imx/common.h    |    3 +++
 arch/arm/mach-imx/gpc.c       |   11 +++++------
 arch/arm/mach-imx/platsmp.c   |   14 ++++++++++++++
 4 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 5f9f591..5ac10a0 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -23,6 +23,10 @@
 #include "clk.h"
 #include "common.h"
 
+#define CCSR				0x0c
+#define BM_CCSR_PLL1_SW_CLK_SEL		(0x1 << 2)
+#define BM_CCSR_STEP_SEL		(0x1 << 8)
+
 #define CCGR0				0x68
 #define CCGR1				0x6c
 #define CCGR2				0x70
@@ -60,22 +64,27 @@ void __init imx6q_clock_map_io(void) { }
 
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
 {
+	static enum mxc_cpu_pwr_mode last_mode;
+	static u32 ccsr;
 	u32 val = readl_relaxed(ccm_base + CLPCR);
 
 	val &= ~BM_CLPCR_LPM;
 	switch (mode) {
 	case WAIT_CLOCKED:
+		/* Restore CCSR changed by WAIT_UNCLOCKED */
+		if (last_mode == WAIT_UNCLOCKED)
+			writel_relaxed(ccsr, ccm_base + CCSR);
 		break;
 	case WAIT_UNCLOCKED:
 		val |= 0x1 << BP_CLPCR_LPM;
-		break;
-	case STOP_POWER_ON:
-		val |= 0x2 << BP_CLPCR_LPM;
+		val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;
+		/* Source arm clock from 24 MHz OSC */
+		ccsr = readl_relaxed(ccm_base + CCSR);
+		writel_relaxed((ccsr | BM_CCSR_PLL1_SW_CLK_SEL) &
+			       ~BM_CCSR_STEP_SEL, ccm_base + CCSR);
 		break;
 	case WAIT_UNCLOCKED_POWER_OFF:
 		val |= 0x1 << BP_CLPCR_LPM;
-		val &= ~BM_CLPCR_VSTBY;
-		val &= ~BM_CLPCR_SBYOS;
 		break;
 	case STOP_POWER_OFF:
 		val |= 0x2 << BP_CLPCR_LPM;
@@ -88,6 +97,19 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
 	}
 
 	writel_relaxed(val, ccm_base + CLPCR);
+	last_mode = mode;
+
+	/* Need to enable SCU standby for entering WAIT modes */
+	if (mode == WAIT_UNCLOCKED || mode == WAIT_UNCLOCKED_POWER_OFF)
+		imx_scu_standby_enable(true);
+	else
+		imx_scu_standby_enable(false);
+
+	/* Tell GPC whether to power off ARM core */
+	if (mode == WAIT_UNCLOCKED_POWER_OFF || mode == STOP_POWER_OFF)
+		imx_gpc_cpu_pdn(true);
+	else
+		imx_gpc_cpu_pdn(false);
 
 	return 0;
 }
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index ef8db6b..9ff0776 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -126,9 +126,11 @@ extern u32 *pl310_get_save_ptr(void);
 extern void v7_secondary_startup(void);
 extern void imx_scu_map_io(void);
 extern void imx_smp_prepare(void);
+extern void imx_scu_standby_enable(bool enable);
 #else
 static inline void imx_scu_map_io(void) {}
 static inline void imx_smp_prepare(void) {}
+static inline void imx_scu_standby_enable(bool enable) {}
 #endif
 extern void imx_enable_cpu(int cpu, bool enable);
 extern void imx_set_cpu_jump(int cpu, void *jump_addr);
@@ -137,6 +139,7 @@ extern void imx_src_prepare_restart(void);
 extern void imx_gpc_init(void);
 extern void imx_gpc_pre_suspend(void);
 extern void imx_gpc_post_resume(void);
+extern void imx_gpc_cpu_pdn(bool);
 extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
 extern void imx6q_clock_map_io(void);
 
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index be9a6cb..897a5af 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -27,14 +27,16 @@ static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
 
+void imx_gpc_cpu_pdn(bool pdn)
+{
+	writel_relaxed(pdn ? 0x1 : 0x0, gpc_base + GPC_PGC_CPU_PDN);
+}
+
 void imx_gpc_pre_suspend(void)
 {
 	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
 	int i;
 
-	/* Tell GPC to power off ARM core when suspend */
-	writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
-
 	for (i = 0; i < IMR_NUM; i++) {
 		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
 		writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);
@@ -46,9 +48,6 @@ void imx_gpc_post_resume(void)
 	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
 	int i;
 
-	/* Keep ARM core powered on for other low-power modes */
-	writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
-
 	for (i = 0; i < IMR_NUM; i++)
 		writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
 }
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 3777b80..c739a8a 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -20,6 +20,8 @@
 #include "common.h"
 #include "hardware.h"
 
+#define SCU_STANDBY_ENABLE	(1 << 5)
+
 static void __iomem *scu_base;
 
 static struct map_desc scu_io_desc __initdata = {
@@ -42,6 +44,18 @@ void __init imx_scu_map_io(void)
 	scu_base = IMX_IO_ADDRESS(base);
 }
 
+void imx_scu_standby_enable(bool enable)
+{
+	u32 val = readl_relaxed(scu_base);
+
+	if (enable)
+		val |= SCU_STANDBY_ENABLE;
+	else
+		val &= ~SCU_STANDBY_ENABLE;
+
+	writel_relaxed(val, scu_base);
+}
+
 static void __cpuinit imx_secondary_init(unsigned int cpu)
 {
 	/*
-- 
1.7.9.5

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

* [PATCH 07/10] ARM: imx6q: get v7_cpu_resume ready for cpuidle
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (5 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 06/10] ARM: imx6q: prepare imx6q_set_lpm for cpudile support Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 08/10] ARM: imx: move imx6q_cpuidle_driver into a separate file Shawn Guo
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

To get v7_cpu_resume ready for cpuidle power gating case, we need the
following changes.

* L2X0_POWER_CTRL register needs to be restored.

* Enable SCU inside v7_cpu_resume.  As the result, function
  imx_smp_prepare gets eliminated.

* Remove v7_invalidate_l1 invoking from v7_cpu_resume.  It turns out
  that v7_invalidate_l1 only needs to be called for secondary cores
  startup.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/common.h   |    2 --
 arch/arm/mach-imx/headsmp.S  |   25 ++++++++++++++++++++++---
 arch/arm/mach-imx/platsmp.c  |    7 +------
 arch/arm/mach-imx/pm-imx6q.c |    1 -
 4 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 9ff0776..ea11bbc 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -125,11 +125,9 @@ extern u32 *pl310_get_save_ptr(void);
 #ifdef CONFIG_SMP
 extern void v7_secondary_startup(void);
 extern void imx_scu_map_io(void);
-extern void imx_smp_prepare(void);
 extern void imx_scu_standby_enable(bool enable);
 #else
 static inline void imx_scu_map_io(void) {}
-static inline void imx_smp_prepare(void) {}
 static inline void imx_scu_standby_enable(bool enable) {}
 #endif
 extern void imx_enable_cpu(int cpu, bool enable);
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index 7e49deb..ac8a967 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -27,8 +27,7 @@
  * clean + invalidate, before jumping into the kernel.
  *
  * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs
- * to be called for both secondary cores startup and primary core resume
- * procedures.  Ideally, it should be moved into arch/arm/mm/cache-v7.S.
+ * to be called for secondary cores startup.
  */
 ENTRY(v7_invalidate_l1)
 	mov	r0, #0
@@ -84,10 +83,16 @@ ENDPROC(v7_secondary_startup)
 	.macro	pl310_resume
 	ldr	r2, phys_l2x0_saved_regs
 	ldr	r0, [r2, #L2X0_R_PHY_BASE]	@ get physical base of l2x0
+	ldr	r1, [r0, #L2X0_CTRL]		@ check if already enabled
+	tst	r1, #1
+	bne	1f
 	ldr	r1, [r2, #L2X0_R_AUX_CTRL]	@ get aux_ctrl value
 	str	r1, [r0, #L2X0_AUX_CTRL]	@ restore aux_ctrl
+	ldr	r1, [r2, #L2X0_R_PWR_CTRL]
+	str	r1, [r0, #L2X0_POWER_CTRL]
 	mov	r1, #0x1
 	str	r1, [r0, #L2X0_CTRL]		@ re-enable L2
+1:
 	.endm
 
 	.globl	phys_l2x0_saved_regs
@@ -98,9 +103,23 @@ phys_l2x0_saved_regs:
 	.endm
 #endif
 
+#ifdef CONFIG_SMP
+	.macro	_scu_enable
+	/* Enable SCU */
+	mrc	p15, 4, r0, c15, c0, 0		@ r0 = scu physical base
+	ldr	r1, [r0]			@ r1 = scu control register
+	tst	r1, #0x1			@ check if already enabled
+	orreq	r1, r1, #0x1
+	streq	r1, [r0]
+	.endm
+#else
+	.macro	_scu_enable
+	.endm
+#endif
+
 ENTRY(v7_cpu_resume)
-	bl	v7_invalidate_l1
 	pl310_resume
+	_scu_enable
 	b	cpu_resume
 ENDPROC(v7_cpu_resume)
 #endif
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index c739a8a..fc25062 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -89,14 +89,9 @@ static void __init imx_smp_init_cpus(void)
 	set_smp_cross_call(gic_raise_softirq);
 }
 
-void imx_smp_prepare(void)
-{
-	scu_enable(scu_base);
-}
-
 static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
 {
-	imx_smp_prepare();
+	scu_enable(scu_base);
 }
 
 struct smp_operations  imx_smp_ops __initdata = {
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
index a17543d..7c4347b 100644
--- a/arch/arm/mach-imx/pm-imx6q.c
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -39,7 +39,6 @@ static int imx6q_pm_enter(suspend_state_t state)
 		imx_set_cpu_jump(0, v7_cpu_resume);
 		/* Zzz ... */
 		cpu_suspend(0, imx6q_suspend_finish);
-		imx_smp_prepare();
 		imx_gpc_post_resume();
 		break;
 	default:
-- 
1.7.9.5

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

* [PATCH 08/10] ARM: imx: move imx6q_cpuidle_driver into a separate file
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (6 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 07/10] ARM: imx6q: get v7_cpu_resume ready for cpuidle Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask() Shawn Guo
  2012-10-23 15:22 ` [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle Shawn Guo
  9 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

Move imx6q_cpuidle_driver into a separate file as more codes will
be added when WAIT mode gets implemented as cpuidle.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Makefile        |    6 +++++-
 arch/arm/mach-imx/cpuidle-imx6q.c |   26 ++++++++++++++++++++++++++
 arch/arm/mach-imx/cpuidle.h       |    5 +++++
 arch/arm/mach-imx/mach-imx6q.c    |   12 +-----------
 4 files changed, 37 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm/mach-imx/cpuidle-imx6q.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index fe47b71..a29ed49 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -28,7 +28,11 @@ obj-$(CONFIG_MXC_ULPI) += ulpi.o
 obj-$(CONFIG_MXC_USE_EPIT) += epit.o
 obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
 obj-$(CONFIG_CPU_FREQ_IMX)    += cpufreq.o
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+
+ifeq ($(CONFIG_CPU_IDLE),y)
+obj-y += cpuidle.o
+obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
+endif
 
 ifdef CONFIG_SND_IMX_SOC
 obj-y += ssi-fiq.o
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
new file mode 100644
index 0000000..83facc9
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+
+#include "cpuidle.h"
+
+static struct cpuidle_driver imx6q_cpuidle_driver = {
+	.name = "imx6q_cpuidle",
+	.owner = THIS_MODULE,
+	.en_core_tk_irqen = 1,
+	.states[0] = ARM_CPUIDLE_WFI_STATE,
+	.state_count = 1,
+};
+
+int __init imx6q_cpuidle_init(void)
+{
+	return imx_cpuidle_init(&imx6q_cpuidle_driver);
+}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index bc932d1..e092d13 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -14,9 +14,14 @@
 
 #ifdef CONFIG_CPU_IDLE
 extern int imx_cpuidle_init(struct cpuidle_driver *drv);
+extern int imx6q_cpuidle_init(void);
 #else
 static inline int imx_cpuidle_init(struct cpuidle_driver *drv)
 {
 	return -ENODEV;
 }
+static inline int imx6q_cpuidle_init(void)
+{
+	return -ENODEV;
+}
 #endif
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 1c5acf8..8ecdeb5 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -12,7 +12,6 @@
 
 #include <linux/clk.h>
 #include <linux/clkdev.h>
-#include <linux/cpuidle.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/init.h>
@@ -26,7 +25,6 @@
 #include <linux/regmap.h>
 #include <linux/micrel_phy.h>
 #include <linux/mfd/syscon.h>
-#include <asm/cpuidle.h>
 #include <asm/smp_twd.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
@@ -182,17 +180,9 @@ static void __init imx6q_init_machine(void)
 	imx6q_usb_init();
 }
 
-static struct cpuidle_driver imx6q_cpuidle_driver = {
-	.name			= "imx6q_cpuidle",
-	.owner			= THIS_MODULE,
-	.en_core_tk_irqen	= 1,
-	.states[0]		= ARM_CPUIDLE_WFI_STATE,
-	.state_count		= 1,
-};
-
 static void __init imx6q_init_late(void)
 {
-	imx_cpuidle_init(&imx6q_cpuidle_driver);
+	imx6q_cpuidle_init();
 }
 
 static void __init imx6q_map_io(void)
-- 
1.7.9.5

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

* [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask()
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (7 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 08/10] ARM: imx: move imx6q_cpuidle_driver into a separate file Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-31  3:43   ` Shawn Guo
  2012-10-23 15:22 ` [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle Shawn Guo
  9 siblings, 1 reply; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

Add function arch_send_wakeup_ipi_mask(), so that platform code can
use it as an easy way to wake up cores that are in WFI.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
---
 arch/arm/include/asm/smp.h |    1 +
 arch/arm/kernel/smp.c      |    5 +++++
 2 files changed, 6 insertions(+)

diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2e3be16..d3a22be 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -79,6 +79,7 @@ extern void cpu_die(void);
 
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
 
 struct smp_operations {
 #ifdef CONFIG_SMP
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 8e20754d..dd5dd02 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -415,6 +415,11 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 	smp_cross_call(mask, IPI_CALL_FUNC);
 }
 
+void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+	smp_cross_call(mask, IPI_WAKEUP);
+}
+
 void arch_send_call_function_single_ipi(int cpu)
 {
 	smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
-- 
1.7.9.5

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

* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
  2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
                   ` (8 preceding siblings ...)
  2012-10-23 15:22 ` [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask() Shawn Guo
@ 2012-10-23 15:22 ` Shawn Guo
  2012-10-23 16:09   ` Lee Robert-B18647
  2012-10-23 17:35   ` Lorenzo Pieralisi
  9 siblings, 2 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

The imx6q has a low power mode named WAIT.  When all cores are in WFI,
imx6q will go into WAIT mode, and whenever there is a wakeup interrupt,
it will exit WAIT mode.  Software can configure hardware behavior during
WAIT mode, clock gating or power gating for ARM core.

This patch adds two more cpuidle states, wait and srpg, implementing
the ARM clock gating and power gating in WAIT mode respectively.  They
are added as coupled cpuidle states.  Though imx6q hardware already
handles sequencing, the voting provided by coupled cpuidle is still
quite useful, which will allow the system to at least get into clock
gating when one cpu wants clock gating and the other wants power gating.

As WAIT mode is broken on TO1.0 silicon, the feature is only provided
for revision later than TO1.0.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Kconfig         |    1 +
 arch/arm/mach-imx/common.h        |    1 +
 arch/arm/mach-imx/cpuidle-imx6q.c |  155 ++++++++++++++++++++++++++++++++++++-
 arch/arm/mach-imx/cpuidle.c       |    3 +
 arch/arm/mach-imx/headsmp.S       |   56 ++++++++++++++
 arch/arm/mach-imx/mach-imx6q.c    |    7 +-
 arch/arm/mach-imx/platsmp.c       |    5 ++
 7 files changed, 225 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 3ce2771..08435a6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -831,6 +831,7 @@ config SOC_IMX6Q
 	bool "i.MX6 Quad support"
 	select ARCH_HAS_CPUFREQ
 	select ARCH_HAS_OPP
+	select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
 	select ARM_CPU_SUSPEND if PM
 	select ARM_ERRATA_743622
 	select ARM_ERRATA_751472
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index ea11bbc..a3fe18b 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -121,6 +121,7 @@ extern void imx_lluart_map_io(void);
 static inline void imx_lluart_map_io(void) {}
 #endif
 extern void v7_cpu_resume(void);
+extern int v7_suspend_finish(unsigned long val);
 extern u32 *pl310_get_save_ptr(void);
 #ifdef CONFIG_SMP
 extern void v7_secondary_startup(void);
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index 83facc9..3acd6ce 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -6,21 +6,172 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clockchips.h>
+#include <linux/cpu_pm.h>
 #include <linux/cpuidle.h>
 #include <linux/module.h>
 #include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
 
+#include "common.h"
 #include "cpuidle.h"
 
+static atomic_t master = ATOMIC_INIT(0);
+static u32 g_diag_reg;
+
+/*
+ * The diagnostic register holds the ARM core errata bits,
+ * which need to be saved and restored.
+ */
+static inline void save_cpu_arch_register(void)
+{
+	asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
+}
+
+static inline void restore_cpu_arch_register(void)
+{
+	asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
+}
+
+#ifdef CONFIG_SMP
+static inline void imx6q_wakeup_other_cpus(int cpu)
+{
+	struct cpumask online = *cpu_online_mask;
+	const struct cpumask *others;
+
+	cpumask_clear_cpu(cpu, &online);
+	others = &online;
+	arch_send_wakeup_ipi_mask(others);
+}
+#else
+static inline void imx6q_wakeup_other_cpus(int cpu) { }
+#endif
+
+static int imx6q_enter_wait(struct cpuidle_device *dev,
+			    struct cpuidle_driver *drv, int index)
+{
+	int cpu = dev->cpu;
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+	if (atomic_inc_return(&master) == num_online_cpus()) {
+		imx6q_set_lpm(WAIT_UNCLOCKED);
+		cpu_do_idle();
+		imx6q_set_lpm(WAIT_CLOCKED);
+	} else {
+		cpu_do_idle();
+	}
+
+	atomic_dec(&master);
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+	/*
+	 * The coupled cpuidle requires all cores exit together.
+	 * Wake up other cores which could still be in idle.
+	 */
+	imx6q_wakeup_other_cpus(cpu);
+
+	return index;
+}
+
+static inline int imx6q_do_srpg(int cpu)
+{
+	imx_set_cpu_jump(cpu, v7_cpu_resume);
+	return cpu_suspend(cpu, v7_suspend_finish);
+}
+
+static int imx6q_enter_srpg(struct cpuidle_device *dev,
+			    struct cpuidle_driver *drv, int index)
+{
+	int cpu = dev->cpu;
+	int ret;
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+	cpu_pm_enter();
+
+	if (atomic_inc_return(&master) == num_online_cpus()) {
+		cpu_cluster_pm_enter();
+		imx6q_set_lpm(WAIT_UNCLOCKED_POWER_OFF);
+	}
+
+	save_cpu_arch_register();
+	ret = imx6q_do_srpg(cpu);
+	/*
+	 * The ret is 0 if it returns from a successful SRPG,
+	 * otherwise it just aborts from there.
+	 */
+	if (!ret) {
+		restore_cpu_arch_register();
+		cpu_pm_exit();
+	}
+
+	if (atomic_dec_return(&master) == num_online_cpus() - 1) {
+		imx6q_set_lpm(WAIT_CLOCKED);
+		if (!ret)
+			cpu_cluster_pm_exit();
+		else
+			/*
+			 * It just aborts from SRPG, so wake up other cores
+			 * to return exit together.
+			 */
+			imx6q_wakeup_other_cpus(cpu);
+	}
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+	return ret ? -EBUSY : index;
+}
+
+/*
+ * For each cpu, setup the broadcast timer because local timer
+ * stops for the states other than WFI.
+ */
+static void imx6q_setup_broadcast_timer(void *arg)
+{
+	int cpu = smp_processor_id();
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
 static struct cpuidle_driver imx6q_cpuidle_driver = {
 	.name = "imx6q_cpuidle",
 	.owner = THIS_MODULE,
 	.en_core_tk_irqen = 1,
-	.states[0] = ARM_CPUIDLE_WFI_STATE,
-	.state_count = 1,
+	.states = {
+		/* WFI */
+		ARM_CPUIDLE_WFI_STATE,
+		/* WAIT */
+		{
+			.exit_latency = 50,
+			.target_residency = 75,
+			.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
+			.enter = imx6q_enter_wait,
+			.name = "WAIT",
+			.desc = "Clock off",
+		},
+		/* SRPG */
+		{
+			.exit_latency = 1000,
+			.target_residency = 1200,
+			.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
+			.enter = imx6q_enter_srpg,
+			.name = "SRPG",
+			.desc = "Power off",
+		},
+	},
+	.state_count = 3,
+	.safe_state_index = 0,
 };
 
 int __init imx6q_cpuidle_init(void)
 {
+	/* Set initial power mode */
+	imx6q_set_lpm(WAIT_CLOCKED);
+
+	/* Configure the broadcast timer on each cpu */
+	on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
+
 	return imx_cpuidle_init(&imx6q_cpuidle_driver);
 }
diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c
index d4cb511..05a537f 100644
--- a/arch/arm/mach-imx/cpuidle.c
+++ b/arch/arm/mach-imx/cpuidle.c
@@ -60,6 +60,9 @@ int __init imx_cpuidle_init(struct cpuidle_driver *drv)
 		dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
 		dev->cpu = cpu_id;
 		dev->state_count = drv->state_count;
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+		dev->coupled_cpus = *cpu_online_mask;
+#endif
 
 		ret = cpuidle_register_device(dev);
 		if (ret) {
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index ac8a967..f920962 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -71,6 +71,62 @@ ENDPROC(v7_secondary_startup)
 #endif
 
 #ifdef CONFIG_PM
+ENTRY(v7_suspend_finish)
+	stmfd	sp!, {r4-r12, lr}
+
+	/* Disable D-cache */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #(1 << 2)		@ clear SCTRL.C
+	mcr	p15, 0, r0, c1, c0, 0
+	isb
+
+	/* Flush D-cache */
+	bl	v7_flush_dcache_louis
+
+#ifdef CONFIG_SMP
+	/* Exit coherency */
+	mrc	p15, 0, r0, c1, c0, 1
+	bic	r0, r0, #(1 << 6)		@ clear ACTLR.SMP
+	mcr	p15, 0, r0, c1, c0, 1
+	isb
+
+	/* Invalidate SCU tag RAM for the cpu */
+	bl	imx_get_scu_base		@ r0 = scu base
+	mrc	p15, 0, r2, c0, c0, 5 		@ r2 = cpu id
+	and	r2, r2, #0xf
+	mov	r2, r2, lsl #2
+	mov	r1, #0xf
+	mov	r1, r1, lsl r2
+	str	r1, [r0, #0xc]
+	dsb
+#endif
+
+	/*
+	 * CPU can speculatively prefetch instructions, so add 16 NOPs
+	 * after WFI per Cortex-A9 pipeline.
+	 */
+	wfi
+	.rept 16
+	nop
+	.endr
+
+	/* Enable D-cache */
+	mrc	p15, 0, r0, c1, c0, 0
+	orr	r0, r0, #(1 << 2)		@ set SCTRL.C
+	mcr	p15, 0, r0, c1, c0, 0
+	isb
+
+#ifdef CONFIG_SMP
+	/* Enter coherency */
+	mrc	p15, 0, r0, c1, c0, 1
+	orr	r0, r0, #(1 << 6) 		@ set ACTLR.SMP
+	mcr	p15, 0, r0, c1, c0, 1
+	isb
+#endif
+
+	ldmfd	sp!, {r4-r12, pc}
+ENDPROC(v7_suspend_finish)
+
 /*
  * The following code is located into the .data section.  This is to
  * allow phys_l2x0_saved_regs to be accessed with a relative load
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 8ecdeb5..9c9dbf8 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -182,7 +182,12 @@ static void __init imx6q_init_machine(void)
 
 static void __init imx6q_init_late(void)
 {
-	imx6q_cpuidle_init();
+	/*
+	 * WAIT mode is broken on TO1.0, so there is no point to
+	 * have cpuidle running on it.
+	 */
+	if (imx6q_revision() > IMX_CHIP_REVISION_1_0)
+		imx6q_cpuidle_init();
 }
 
 static void __init imx6q_map_io(void)
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index fc25062..dcd590b 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -24,6 +24,11 @@
 
 static void __iomem *scu_base;
 
+void __iomem *imx_get_scu_base(void)
+{
+	return scu_base;
+}
+
 static struct map_desc scu_io_desc __initdata = {
 	/* .virtual and .pfn are run-time assigned */
 	.length		= SZ_4K,
-- 
1.7.9.5

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

* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
  2012-10-23 15:22 ` [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle Shawn Guo
@ 2012-10-23 16:09   ` Lee Robert-B18647
  2012-10-24 14:04     ` Shawn Guo
  2012-10-23 17:35   ` Lorenzo Pieralisi
  1 sibling, 1 reply; 26+ messages in thread
From: Lee Robert-B18647 @ 2012-10-23 16:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hey Shawn,

For your SRPG implementation, a couple of weeks ago an issue was found that affects all i.MX6 SRPG functionality that requires a work around for 100% reliable operation.  It's my understanding that the workaround is almost but not yet finalized.  Ranjani is most familiar with this issue so you and her can discuss further.

Best Regards,
Rob

> -----Original Message-----
> From: Shawn Guo [mailto:shawn.guo at linaro.org]
> Sent: Tuesday, October 23, 2012 10:23 AM
> To: linux-arm-kernel at lists.infradead.org
> Cc: Sascha Hauer; Lee Robert-B18647; Shawn Guo
> Subject: [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled
> cpuidle
> 
> The imx6q has a low power mode named WAIT.  When all cores are in WFI,
> imx6q will go into WAIT mode, and whenever there is a wakeup interrupt,
> it will exit WAIT mode.  Software can configure hardware behavior
> during WAIT mode, clock gating or power gating for ARM core.
> 
> This patch adds two more cpuidle states, wait and srpg, implementing
> the ARM clock gating and power gating in WAIT mode respectively.  They
> are added as coupled cpuidle states.  Though imx6q hardware already
> handles sequencing, the voting provided by coupled cpuidle is still
> quite useful, which will allow the system to at least get into clock
> gating when one cpu wants clock gating and the other wants power
> gating.
> 
> As WAIT mode is broken on TO1.0 silicon, the feature is only provided
> for revision later than TO1.0.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  arch/arm/mach-imx/Kconfig         |    1 +
>  arch/arm/mach-imx/common.h        |    1 +
>  arch/arm/mach-imx/cpuidle-imx6q.c |  155
> ++++++++++++++++++++++++++++++++++++-
>  arch/arm/mach-imx/cpuidle.c       |    3 +
>  arch/arm/mach-imx/headsmp.S       |   56 ++++++++++++++
>  arch/arm/mach-imx/mach-imx6q.c    |    7 +-
>  arch/arm/mach-imx/platsmp.c       |    5 ++
>  7 files changed, 225 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index 3ce2771..08435a6 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -831,6 +831,7 @@ config SOC_IMX6Q
>  	bool "i.MX6 Quad support"
>  	select ARCH_HAS_CPUFREQ
>  	select ARCH_HAS_OPP
> +	select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
>  	select ARM_CPU_SUSPEND if PM
>  	select ARM_ERRATA_743622
>  	select ARM_ERRATA_751472
> diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
> index ea11bbc..a3fe18b 100644
> --- a/arch/arm/mach-imx/common.h
> +++ b/arch/arm/mach-imx/common.h
> @@ -121,6 +121,7 @@ extern void imx_lluart_map_io(void);  static inline
> void imx_lluart_map_io(void) {}  #endif  extern void
> v7_cpu_resume(void);
> +extern int v7_suspend_finish(unsigned long val);
>  extern u32 *pl310_get_save_ptr(void);
>  #ifdef CONFIG_SMP
>  extern void v7_secondary_startup(void); diff --git a/arch/arm/mach-
> imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
> index 83facc9..3acd6ce 100644
> --- a/arch/arm/mach-imx/cpuidle-imx6q.c
> +++ b/arch/arm/mach-imx/cpuidle-imx6q.c
> @@ -6,21 +6,172 @@
>   * published by the Free Software Foundation.
>   */
> 
> +#include <linux/clockchips.h>
> +#include <linux/cpu_pm.h>
>  #include <linux/cpuidle.h>
>  #include <linux/module.h>
>  #include <asm/cpuidle.h>
> +#include <asm/proc-fns.h>
> +#include <asm/suspend.h>
> 
> +#include "common.h"
>  #include "cpuidle.h"
> 
> +static atomic_t master = ATOMIC_INIT(0); static u32 g_diag_reg;
> +
> +/*
> + * The diagnostic register holds the ARM core errata bits,
> + * which need to be saved and restored.
> + */
> +static inline void save_cpu_arch_register(void) {
> +	asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc"); }
> +
> +static inline void restore_cpu_arch_register(void) {
> +	asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc"); }
> +
> +#ifdef CONFIG_SMP
> +static inline void imx6q_wakeup_other_cpus(int cpu) {
> +	struct cpumask online = *cpu_online_mask;
> +	const struct cpumask *others;
> +
> +	cpumask_clear_cpu(cpu, &online);
> +	others = &online;
> +	arch_send_wakeup_ipi_mask(others);
> +}
> +#else
> +static inline void imx6q_wakeup_other_cpus(int cpu) { } #endif
> +
> +static int imx6q_enter_wait(struct cpuidle_device *dev,
> +			    struct cpuidle_driver *drv, int index) {
> +	int cpu = dev->cpu;
> +
> +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
> +
> +	if (atomic_inc_return(&master) == num_online_cpus()) {
> +		imx6q_set_lpm(WAIT_UNCLOCKED);
> +		cpu_do_idle();
> +		imx6q_set_lpm(WAIT_CLOCKED);
> +	} else {
> +		cpu_do_idle();
> +	}
> +
> +	atomic_dec(&master);
> +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
> +
> +	/*
> +	 * The coupled cpuidle requires all cores exit together.
> +	 * Wake up other cores which could still be in idle.
> +	 */
> +	imx6q_wakeup_other_cpus(cpu);
> +
> +	return index;
> +}
> +
> +static inline int imx6q_do_srpg(int cpu) {
> +	imx_set_cpu_jump(cpu, v7_cpu_resume);
> +	return cpu_suspend(cpu, v7_suspend_finish); }
> +
> +static int imx6q_enter_srpg(struct cpuidle_device *dev,
> +			    struct cpuidle_driver *drv, int index) {
> +	int cpu = dev->cpu;
> +	int ret;
> +
> +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
> +
> +	cpu_pm_enter();
> +
> +	if (atomic_inc_return(&master) == num_online_cpus()) {
> +		cpu_cluster_pm_enter();
> +		imx6q_set_lpm(WAIT_UNCLOCKED_POWER_OFF);
> +	}
> +
> +	save_cpu_arch_register();
> +	ret = imx6q_do_srpg(cpu);
> +	/*
> +	 * The ret is 0 if it returns from a successful SRPG,
> +	 * otherwise it just aborts from there.
> +	 */
> +	if (!ret) {
> +		restore_cpu_arch_register();
> +		cpu_pm_exit();
> +	}
> +
> +	if (atomic_dec_return(&master) == num_online_cpus() - 1) {
> +		imx6q_set_lpm(WAIT_CLOCKED);
> +		if (!ret)
> +			cpu_cluster_pm_exit();
> +		else
> +			/*
> +			 * It just aborts from SRPG, so wake up other cores
> +			 * to return exit together.
> +			 */
> +			imx6q_wakeup_other_cpus(cpu);
> +	}
> +
> +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
> +
> +	return ret ? -EBUSY : index;
> +}
> +
> +/*
> + * For each cpu, setup the broadcast timer because local timer
> + * stops for the states other than WFI.
> + */
> +static void imx6q_setup_broadcast_timer(void *arg) {
> +	int cpu = smp_processor_id();
> +
> +	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); }
> +
>  static struct cpuidle_driver imx6q_cpuidle_driver = {
>  	.name = "imx6q_cpuidle",
>  	.owner = THIS_MODULE,
>  	.en_core_tk_irqen = 1,
> -	.states[0] = ARM_CPUIDLE_WFI_STATE,
> -	.state_count = 1,
> +	.states = {
> +		/* WFI */
> +		ARM_CPUIDLE_WFI_STATE,
> +		/* WAIT */
> +		{
> +			.exit_latency = 50,
> +			.target_residency = 75,
> +			.flags = CPUIDLE_FLAG_TIME_VALID |
> CPUIDLE_FLAG_COUPLED,
> +			.enter = imx6q_enter_wait,
> +			.name = "WAIT",
> +			.desc = "Clock off",
> +		},
> +		/* SRPG */
> +		{
> +			.exit_latency = 1000,
> +			.target_residency = 1200,
> +			.flags = CPUIDLE_FLAG_TIME_VALID |
> CPUIDLE_FLAG_COUPLED,
> +			.enter = imx6q_enter_srpg,
> +			.name = "SRPG",
> +			.desc = "Power off",
> +		},
> +	},
> +	.state_count = 3,
> +	.safe_state_index = 0,
>  };
> 
>  int __init imx6q_cpuidle_init(void)
>  {
> +	/* Set initial power mode */
> +	imx6q_set_lpm(WAIT_CLOCKED);
> +
> +	/* Configure the broadcast timer on each cpu */
> +	on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
> +
>  	return imx_cpuidle_init(&imx6q_cpuidle_driver);
>  }
> diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c
> index d4cb511..05a537f 100644
> --- a/arch/arm/mach-imx/cpuidle.c
> +++ b/arch/arm/mach-imx/cpuidle.c
> @@ -60,6 +60,9 @@ int __init imx_cpuidle_init(struct cpuidle_driver
> *drv)
>  		dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
>  		dev->cpu = cpu_id;
>  		dev->state_count = drv->state_count;
> +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
> +		dev->coupled_cpus = *cpu_online_mask; #endif
> 
>  		ret = cpuidle_register_device(dev);
>  		if (ret) {
> diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
> index ac8a967..f920962 100644
> --- a/arch/arm/mach-imx/headsmp.S
> +++ b/arch/arm/mach-imx/headsmp.S
> @@ -71,6 +71,62 @@ ENDPROC(v7_secondary_startup)  #endif
> 
>  #ifdef CONFIG_PM
> +ENTRY(v7_suspend_finish)
> +	stmfd	sp!, {r4-r12, lr}
> +
> +	/* Disable D-cache */
> +	mrc	p15, 0, r0, c1, c0, 0
> +	bic	r0, r0, #(1 << 2)		@ clear SCTRL.C
> +	mcr	p15, 0, r0, c1, c0, 0
> +	isb
> +
> +	/* Flush D-cache */
> +	bl	v7_flush_dcache_louis
> +
> +#ifdef CONFIG_SMP
> +	/* Exit coherency */
> +	mrc	p15, 0, r0, c1, c0, 1
> +	bic	r0, r0, #(1 << 6)		@ clear ACTLR.SMP
> +	mcr	p15, 0, r0, c1, c0, 1
> +	isb
> +
> +	/* Invalidate SCU tag RAM for the cpu */
> +	bl	imx_get_scu_base		@ r0 = scu base
> +	mrc	p15, 0, r2, c0, c0, 5 		@ r2 = cpu id
> +	and	r2, r2, #0xf
> +	mov	r2, r2, lsl #2
> +	mov	r1, #0xf
> +	mov	r1, r1, lsl r2
> +	str	r1, [r0, #0xc]
> +	dsb
> +#endif
> +
> +	/*
> +	 * CPU can speculatively prefetch instructions, so add 16 NOPs
> +	 * after WFI per Cortex-A9 pipeline.
> +	 */
> +	wfi
> +	.rept 16
> +	nop
> +	.endr
> +
> +	/* Enable D-cache */
> +	mrc	p15, 0, r0, c1, c0, 0
> +	orr	r0, r0, #(1 << 2)		@ set SCTRL.C
> +	mcr	p15, 0, r0, c1, c0, 0
> +	isb
> +
> +#ifdef CONFIG_SMP
> +	/* Enter coherency */
> +	mrc	p15, 0, r0, c1, c0, 1
> +	orr	r0, r0, #(1 << 6) 		@ set ACTLR.SMP
> +	mcr	p15, 0, r0, c1, c0, 1
> +	isb
> +#endif
> +
> +	ldmfd	sp!, {r4-r12, pc}
> +ENDPROC(v7_suspend_finish)
> +
>  /*
>   * The following code is located into the .data section.  This is to
>   * allow phys_l2x0_saved_regs to be accessed with a relative load diff
> --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> index 8ecdeb5..9c9dbf8 100644
> --- a/arch/arm/mach-imx/mach-imx6q.c
> +++ b/arch/arm/mach-imx/mach-imx6q.c
> @@ -182,7 +182,12 @@ static void __init imx6q_init_machine(void)
> 
>  static void __init imx6q_init_late(void)  {
> -	imx6q_cpuidle_init();
> +	/*
> +	 * WAIT mode is broken on TO1.0, so there is no point to
> +	 * have cpuidle running on it.
> +	 */
> +	if (imx6q_revision() > IMX_CHIP_REVISION_1_0)
> +		imx6q_cpuidle_init();
>  }
> 
>  static void __init imx6q_map_io(void)
> diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
> index fc25062..dcd590b 100644
> --- a/arch/arm/mach-imx/platsmp.c
> +++ b/arch/arm/mach-imx/platsmp.c
> @@ -24,6 +24,11 @@
> 
>  static void __iomem *scu_base;
> 
> +void __iomem *imx_get_scu_base(void)
> +{
> +	return scu_base;
> +}
> +
>  static struct map_desc scu_io_desc __initdata = {
>  	/* .virtual and .pfn are run-time assigned */
>  	.length		= SZ_4K,
> --
> 1.7.9.5
> 

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

* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
  2012-10-23 15:22 ` [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle Shawn Guo
  2012-10-23 16:09   ` Lee Robert-B18647
@ 2012-10-23 17:35   ` Lorenzo Pieralisi
  2012-10-24 13:57     ` Shawn Guo
  1 sibling, 1 reply; 26+ messages in thread
From: Lorenzo Pieralisi @ 2012-10-23 17:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Oct 23, 2012 at 04:22:59PM +0100, Shawn Guo wrote:

[...]

> +/*
> + * For each cpu, setup the broadcast timer because local timer
> + * stops for the states other than WFI.
> + */
> +static void imx6q_setup_broadcast_timer(void *arg)
> +{
> +       int cpu = smp_processor_id();
> +
> +       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
> +}

Can anyone explain to me please why this is needed ?

Is this snippet not enough ? If not why ?

clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);

[cpu sleep - power down]

clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);

Thanks,
Lorenzo

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

* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
  2012-10-23 17:35   ` Lorenzo Pieralisi
@ 2012-10-24 13:57     ` Shawn Guo
  2012-10-24 15:29       ` Lorenzo Pieralisi
  0 siblings, 1 reply; 26+ messages in thread
From: Shawn Guo @ 2012-10-24 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Oct 23, 2012 at 06:35:43PM +0100, Lorenzo Pieralisi wrote:
> On Tue, Oct 23, 2012 at 04:22:59PM +0100, Shawn Guo wrote:
> 
> [...]
> 
> > +/*
> > + * For each cpu, setup the broadcast timer because local timer
> > + * stops for the states other than WFI.
> > + */
> > +static void imx6q_setup_broadcast_timer(void *arg)
> > +{
> > +       int cpu = smp_processor_id();
> > +
> > +       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
> > +}
> 
> Can anyone explain to me please why this is needed ?
> 
It basically does nothing if either NO_HZ or HIGH_RES_TIMERS is
enabled, in which case tick_broadcast_setup_oneshot is already called
on init_timers path to set up bc->event_handler.  This is the general
case since nowadays we have both options enabled by default for most
systems.

However if neither option is enabled, CLOCK_EVT_NOTIFY_BROADCAST_ON
notifying will help route to call tick_broadcast_setup_oneshot to have
bc->event_handler set up.

So in short, it's needed to have broadcast timer work as expected when
neither NO_HZ or HIGH_RES_TIMERS is enabled.

Shawn

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

* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
  2012-10-23 16:09   ` Lee Robert-B18647
@ 2012-10-24 14:04     ` Shawn Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-10-24 14:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Oct 23, 2012 at 04:09:08PM +0000, Lee Robert-B18647 wrote:
> Hey Shawn,
> 
> For your SRPG implementation, a couple of weeks ago an issue was found that affects all i.MX6 SRPG functionality that requires a work around for 100% reliable operation.  It's my understanding that the workaround is almost but not yet finalized.  Ranjani is most familiar with this issue so you and her can discuss further.
> 
Thanks for the info, Rob.

I worked with Anson today trying to reproduce the issue with my kernel
on imx6q.  But so far, we can not reproduce it.  So I would have the
series go as it is, and we can add workaround later when we see the
real failure on imx6q to keep the history clear.

Shawn

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

* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
  2012-10-24 13:57     ` Shawn Guo
@ 2012-10-24 15:29       ` Lorenzo Pieralisi
  0 siblings, 0 replies; 26+ messages in thread
From: Lorenzo Pieralisi @ 2012-10-24 15:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 24, 2012 at 02:57:31PM +0100, Shawn Guo wrote:
> On Tue, Oct 23, 2012 at 06:35:43PM +0100, Lorenzo Pieralisi wrote:
> > On Tue, Oct 23, 2012 at 04:22:59PM +0100, Shawn Guo wrote:
> > 
> > [...]
> > 
> > > +/*
> > > + * For each cpu, setup the broadcast timer because local timer
> > > + * stops for the states other than WFI.
> > > + */
> > > +static void imx6q_setup_broadcast_timer(void *arg)
> > > +{
> > > +       int cpu = smp_processor_id();
> > > +
> > > +       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
> > > +}
> > 
> > Can anyone explain to me please why this is needed ?
> > 
> It basically does nothing if either NO_HZ or HIGH_RES_TIMERS is
> enabled, in which case tick_broadcast_setup_oneshot is already called
> on init_timers path to set up bc->event_handler.  This is the general
> case since nowadays we have both options enabled by default for most
> systems.
> 
> However if neither option is enabled, CLOCK_EVT_NOTIFY_BROADCAST_ON
> notifying will help route to call tick_broadcast_setup_oneshot to have
> bc->event_handler set up.
> 
> So in short, it's needed to have broadcast timer work as expected when
> neither NO_HZ or HIGH_RES_TIMERS is enabled.

Ok, point taken, it was just to check I was not missing anything on the
expected usage on systems where those options are enabled.

Thanks a lot,
Lorenzo

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

* [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask()
  2012-10-23 15:22 ` [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask() Shawn Guo
@ 2012-10-31  3:43   ` Shawn Guo
  2012-11-02 13:42     ` Shawn Guo
  0 siblings, 1 reply; 26+ messages in thread
From: Shawn Guo @ 2012-10-31  3:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Oct 23, 2012 at 11:22:58PM +0800, Shawn Guo wrote:
> Add function arch_send_wakeup_ipi_mask(), so that platform code can
> use it as an easy way to wake up cores that are in WFI.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>

Hi Russell,

Can I ask for your ack to have the patch go via arm-soc being part
of the series?

Shawn

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

* [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask()
  2012-10-31  3:43   ` Shawn Guo
@ 2012-11-02 13:42     ` Shawn Guo
  2012-11-06  3:18       ` Shawn Guo
  0 siblings, 1 reply; 26+ messages in thread
From: Shawn Guo @ 2012-11-02 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 31, 2012 at 11:43:34AM +0800, Shawn Guo wrote:
> On Tue, Oct 23, 2012 at 11:22:58PM +0800, Shawn Guo wrote:
> > Add function arch_send_wakeup_ipi_mask(), so that platform code can
> > use it as an easy way to wake up cores that are in WFI.
> > 
> > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > Cc: Russell King <linux@arm.linux.org.uk>
> 
> Hi Russell,
> 
> Can I ask for your ack to have the patch go via arm-soc being part
> of the series?
> 
Ping

Shawn

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

* [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask()
  2012-11-02 13:42     ` Shawn Guo
@ 2012-11-06  3:18       ` Shawn Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-11-06  3:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Nov 02, 2012 at 09:42:24PM +0800, Shawn Guo wrote:
> On Wed, Oct 31, 2012 at 11:43:34AM +0800, Shawn Guo wrote:
> > On Tue, Oct 23, 2012 at 11:22:58PM +0800, Shawn Guo wrote:
> > > Add function arch_send_wakeup_ipi_mask(), so that platform code can
> > > use it as an easy way to wake up cores that are in WFI.
> > > 
> > > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > > Cc: Russell King <linux@arm.linux.org.uk>
> > 
> > Hi Russell,
> > 
> > Can I ask for your ack to have the patch go via arm-soc being part
> > of the series?
> > 
> Ping
> 
Okay, just tried another way around - put it into patch track system.

Shawn

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

* [PATCH 01/10] ARM: imx6q: print silicon version on boot
  2012-10-23 15:22 ` [PATCH 01/10] ARM: imx6q: print silicon version on boot Shawn Guo
@ 2012-11-15 18:09   ` Moseley, Drew
  2012-11-16  2:23     ` Shawn Guo
  0 siblings, 1 reply; 26+ messages in thread
From: Moseley, Drew @ 2012-11-15 18:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Oct 23, 2012, at 11:22 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> i.MX6Q has 3 revisions 1.0, 1.1 and 1.2.  Print revision on boot.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> arch/arm/mach-imx/mach-imx6q.c |   28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
> 

Hi Shawn,

An addition to this patch to add some error checking.  Thoughts?

Drew




Add error checking to imx6q_revision()

Signed-off-by: Drew Moseley <drew_moseley@mentor.com>
---
 arch/arm/mach-imx/mach-imx6q.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 265c311..072e32a 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -54,9 +54,16 @@ static int imx6q_revision(void)
 
 	if (!rev) {
 		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
+		if (!np)
+			return IMX_CHIP_REVISION_UNKNOWN;
 		base = of_iomap(np, 0);
+		if (!base) {
+			of_node_put(np);
+			return IMX_CHIP_REVISION_UNKNOWN;
+		}
 		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG);
 		iounmap(base);
+		of_node_put(np);
 	}
 
 	switch (rev & 0xff) {
-- 
1.8.0

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

* [PATCH 01/10] ARM: imx6q: print silicon version on boot
  2012-11-15 18:09   ` Moseley, Drew
@ 2012-11-16  2:23     ` Shawn Guo
  2012-11-16  6:25       ` Dirk Behme
  2012-11-16  6:39       ` Shawn Guo
  0 siblings, 2 replies; 26+ messages in thread
From: Shawn Guo @ 2012-11-16  2:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 15, 2012 at 06:09:31PM +0000, Moseley, Drew wrote:
> On Oct 23, 2012, at 11:22 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> > i.MX6Q has 3 revisions 1.0, 1.1 and 1.2.  Print revision on boot.
> > 
> > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > ---
> > arch/arm/mach-imx/mach-imx6q.c |   28 ++++++++++++++++++++++++++++
> > 1 file changed, 28 insertions(+)
> > 
> 
> Hi Shawn,
> 
> An addition to this patch to add some error checking.  Thoughts?
> 
It looks good.  I just squashed the changes into the original patch
with your sob added.  Thanks.

Note, the patch series will probably postponed to 3.9 due to the
dependency on other tree and the fact that I wait for a TO1.2 hardware
to test the power gating state.

Shawn

> Drew
> 
> 
> 
> 
> Add error checking to imx6q_revision()
> 
> Signed-off-by: Drew Moseley <drew_moseley@mentor.com>
> ---
>  arch/arm/mach-imx/mach-imx6q.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> index 265c311..072e32a 100644
> --- a/arch/arm/mach-imx/mach-imx6q.c
> +++ b/arch/arm/mach-imx/mach-imx6q.c
> @@ -54,9 +54,16 @@ static int imx6q_revision(void)
>  
>  	if (!rev) {
>  		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
> +		if (!np)
> +			return IMX_CHIP_REVISION_UNKNOWN;
>  		base = of_iomap(np, 0);
> +		if (!base) {
> +			of_node_put(np);
> +			return IMX_CHIP_REVISION_UNKNOWN;
> +		}
>  		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG);
>  		iounmap(base);
> +		of_node_put(np);
>  	}
>  
>  	switch (rev & 0xff) {
> -- 
> 1.8.0
> 

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

* [PATCH 01/10] ARM: imx6q: print silicon version on boot
  2012-11-16  2:23     ` Shawn Guo
@ 2012-11-16  6:25       ` Dirk Behme
  2012-11-16  6:54         ` Shawn Guo
  2012-11-16  6:39       ` Shawn Guo
  1 sibling, 1 reply; 26+ messages in thread
From: Dirk Behme @ 2012-11-16  6:25 UTC (permalink / raw)
  To: linux-arm-kernel

Am 16.11.2012 03:23, schrieb Shawn Guo:
> On Thu, Nov 15, 2012 at 06:09:31PM +0000, Moseley, Drew wrote:
>> On Oct 23, 2012, at 11:22 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
>>> i.MX6Q has 3 revisions 1.0, 1.1 and 1.2.  Print revision on boot.
>>>
>>> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
>>> ---
>>> arch/arm/mach-imx/mach-imx6q.c |   28 ++++++++++++++++++++++++++++
>>> 1 file changed, 28 insertions(+)
>>>
>>
>> Hi Shawn,
>>
>> An addition to this patch to add some error checking.  Thoughts?
>>
> It looks good.  I just squashed the changes into the original patch
> with your sob added.  Thanks.

Just a small note on the whole series:

We picked the two patches

ARM: imx6q: print silicon version on boot
ARM: imx6q: select ARM and PL310 errata

because they look generic and generally useful. Not only for the 
cpuidle feature.

Maybe it makes sense to apply these two patches independent from the 
cpuidle series as general improvements?

Best regards

Dirk

> Note, the patch series will probably postponed to 3.9 due to the
> dependency on other tree and the fact that I wait for a TO1.2 hardware
> to test the power gating state.
>
> Shawn
>
>> Drew
>>
>>
>>
>>
>> Add error checking to imx6q_revision()
>>
>> Signed-off-by: Drew Moseley <drew_moseley@mentor.com>
>> ---
>>   arch/arm/mach-imx/mach-imx6q.c | 7 +++++++
>>   1 file changed, 7 insertions(+)
>>
>> diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
>> index 265c311..072e32a 100644
>> --- a/arch/arm/mach-imx/mach-imx6q.c
>> +++ b/arch/arm/mach-imx/mach-imx6q.c
>> @@ -54,9 +54,16 @@ static int imx6q_revision(void)
>>
>>   	if (!rev) {
>>   		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
>> +		if (!np)
>> +			return IMX_CHIP_REVISION_UNKNOWN;
>>   		base = of_iomap(np, 0);
>> +		if (!base) {
>> +			of_node_put(np);
>> +			return IMX_CHIP_REVISION_UNKNOWN;
>> +		}
>>   		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG);
>>   		iounmap(base);
>> +		of_node_put(np);
>>   	}
>>
>>   	switch (rev & 0xff) {
>> --
>> 1.8.0
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

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

* [PATCH 01/10] ARM: imx6q: print silicon version on boot
  2012-11-16  2:23     ` Shawn Guo
  2012-11-16  6:25       ` Dirk Behme
@ 2012-11-16  6:39       ` Shawn Guo
  1 sibling, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-11-16  6:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Nov 16, 2012 at 10:23:54AM +0800, Shawn Guo wrote:
> On Thu, Nov 15, 2012 at 06:09:31PM +0000, Moseley, Drew wrote:
> > On Oct 23, 2012, at 11:22 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> > > i.MX6Q has 3 revisions 1.0, 1.1 and 1.2.  Print revision on boot.
> > > 
> > > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > > ---
> > > arch/arm/mach-imx/mach-imx6q.c |   28 ++++++++++++++++++++++++++++
> > > 1 file changed, 28 insertions(+)
> > > 
> > 
> > Hi Shawn,
> > 
> > An addition to this patch to add some error checking.  Thoughts?
> > 
> It looks good.  I just squashed the changes into the original patch
> with your sob added.  Thanks.
> 
> Note, the patch series will probably postponed to 3.9 due to the
> dependency on other tree and the fact that I wait for a TO1.2 hardware
> to test the power gating state.
> 
It seems this particular patch is useful regardless of the cpuidle
support, so I will send this one for 3.8 anyway.

Shawn

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

* [PATCH 01/10] ARM: imx6q: print silicon version on boot
  2012-11-16  6:25       ` Dirk Behme
@ 2012-11-16  6:54         ` Shawn Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2012-11-16  6:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Nov 16, 2012 at 07:25:30AM +0100, Dirk Behme wrote:
> Just a small note on the whole series:
> 
> We picked the two patches
> 
> ARM: imx6q: print silicon version on boot
> ARM: imx6q: select ARM and PL310 errata
> 
> because they look generic and generally useful. Not only for the
> cpuidle feature.
> 
> Maybe it makes sense to apply these two patches independent from the
> cpuidle series as general improvements?
> 
Ok, will send both patch for 3.8.

Shawn

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

* [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata
  2012-10-23 15:22 ` [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata Shawn Guo
@ 2013-11-28 12:44   ` Dirk Behme
  2013-11-29  2:10     ` Shawn Guo
  0 siblings, 1 reply; 26+ messages in thread
From: Dirk Behme @ 2013-11-28 12:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 23.10.2012 17:22, Shawn Guo wrote:
> ARM core r2p10 and PL310 r3p2 are integrated on imx6q.  Select
> corresponding errata.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>   arch/arm/mach-imx/Kconfig |    8 ++++++++
>   1 file changed, 8 insertions(+)
>
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index 4f73866..3ce2771 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
...
> @@ -843,6 +848,9 @@ config SOC_IMX6Q
>   	select MFD_SYSCON
>   	select PINCTRL
>   	select PINCTRL_IMX6Q
> +	select PL310_ERRATA_588369 if CACHE_PL310
> +	select PL310_ERRATA_727915 if CACHE_PL310
> +	select PL310_ERRATA_769419 if CACHE_PL310
>   	select PM_OPP if PM

Just a question: To my understanding, the PL310 on i.MX6D/Q is 
r3p1-50rel0 and on i.MX6DL/SOLO/SL is r3p2.

The PL310 errata I've (Document Revision: 12.1, 14-Apr-2011) states that 
588369 and 727915 don't apply to the PL310 revisions r3p1-50rel0/r3p2. 
So I would think that we don't have to select them for SOC_IMX6Q.

Have I missed anything?

Best regards

Dirk

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

* [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata
  2013-11-28 12:44   ` Dirk Behme
@ 2013-11-29  2:10     ` Shawn Guo
  0 siblings, 0 replies; 26+ messages in thread
From: Shawn Guo @ 2013-11-29  2:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 28, 2013 at 01:44:16PM +0100, Dirk Behme wrote:
> On 23.10.2012 17:22, Shawn Guo wrote:
> >ARM core r2p10 and PL310 r3p2 are integrated on imx6q.  Select
> >corresponding errata.
> >
> >Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> >---
> >  arch/arm/mach-imx/Kconfig |    8 ++++++++
> >  1 file changed, 8 insertions(+)
> >
> >diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> >index 4f73866..3ce2771 100644
> >--- a/arch/arm/mach-imx/Kconfig
> >+++ b/arch/arm/mach-imx/Kconfig
> ...
> >@@ -843,6 +848,9 @@ config SOC_IMX6Q
> >  	select MFD_SYSCON
> >  	select PINCTRL
> >  	select PINCTRL_IMX6Q
> >+	select PL310_ERRATA_588369 if CACHE_PL310
> >+	select PL310_ERRATA_727915 if CACHE_PL310
> >+	select PL310_ERRATA_769419 if CACHE_PL310
> >  	select PM_OPP if PM
> 
> Just a question: To my understanding, the PL310 on i.MX6D/Q is
> r3p1-50rel0 and on i.MX6DL/SOLO/SL is r3p2.
> 
> The PL310 errata I've (Document Revision: 12.1, 14-Apr-2011) states
> that 588369 and 727915 don't apply to the PL310 revisions
> r3p1-50rel0/r3p2. So I would think that we don't have to select them
> for SOC_IMX6Q.
> 
> Have I missed anything?

Hmm, I have forgot the exact reason why I selected these, probably
because the help text of the errata Kconfig options do not specify any
particular revision that is affected.  If a formal PL310 errata
document suggests so, we should probably just drop the items (with
some testing to ensure no regression is caused).

BTW, is the PL310 errata publicly available somewhere?

Shawn

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

end of thread, other threads:[~2013-11-29  2:10 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-23 15:22 [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle Shawn Guo
2012-10-23 15:22 ` [PATCH 01/10] ARM: imx6q: print silicon version on boot Shawn Guo
2012-11-15 18:09   ` Moseley, Drew
2012-11-16  2:23     ` Shawn Guo
2012-11-16  6:25       ` Dirk Behme
2012-11-16  6:54         ` Shawn Guo
2012-11-16  6:39       ` Shawn Guo
2012-10-23 15:22 ` [PATCH 02/10] ARM: imx: allow timer counter to roll over Shawn Guo
2012-10-23 15:22 ` [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata Shawn Guo
2013-11-28 12:44   ` Dirk Behme
2013-11-29  2:10     ` Shawn Guo
2012-10-23 15:22 ` [PATCH 04/10] ARM: imx: initialize cpu power up counters Shawn Guo
2012-10-23 15:22 ` [PATCH 05/10] ARM: imx: mask gpc interrupts initially Shawn Guo
2012-10-23 15:22 ` [PATCH 06/10] ARM: imx6q: prepare imx6q_set_lpm for cpudile support Shawn Guo
2012-10-23 15:22 ` [PATCH 07/10] ARM: imx6q: get v7_cpu_resume ready for cpuidle Shawn Guo
2012-10-23 15:22 ` [PATCH 08/10] ARM: imx: move imx6q_cpuidle_driver into a separate file Shawn Guo
2012-10-23 15:22 ` [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask() Shawn Guo
2012-10-31  3:43   ` Shawn Guo
2012-11-02 13:42     ` Shawn Guo
2012-11-06  3:18       ` Shawn Guo
2012-10-23 15:22 ` [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle Shawn Guo
2012-10-23 16:09   ` Lee Robert-B18647
2012-10-24 14:04     ` Shawn Guo
2012-10-23 17:35   ` Lorenzo Pieralisi
2012-10-24 13:57     ` Shawn Guo
2012-10-24 15:29       ` Lorenzo Pieralisi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.