* [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.