All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] MCPM backend for Exynos5420
@ 2014-04-26 16:05 ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

This is v3 of the series adding MCPM backend support for SMP secondary boot
and core switching on Samsung's Exynos5420. The patches are based on the mcpm
support added for Exynos5420 in the Chromium kernel repository here:
https://chromium.googlesource.com/chromiumos/third_party/kernel-next/+/chromeos-3.8

This patchset depends on:
- ARM: EXYNOS: Map SYSRAM address through DT
(http://www.spinics.net/lists/arm-kernel/msg323011.html)

The patches have been prepared on linux-next(20140424) and tested on SMDK5420
EVT1 using the "/dev/b.L_switcher" user interface. Secondary core bring-up has
also been tested on an Exynos5420-based chromebook.

Changes since v2:
Addressed the following comments from Nicolas Pitre and Daniel Lezcano
	- Added generic common (cluster) configuration functions to pm.c
	  which may be used by other subsystems.
	- Removed unused "cpumask" variable in mcpm code.
	- Re-worked exynos_power_down_finish() referencing the tc2_pm code.
	- Removed the status checks in core and cluster power functions. We
	  just set the power control bit and do not check the previous state
	  anymore.
	- Removed incorrect jiffies timeout usage in path where IRQs are
	  disabled.

Changes since v1:
Addressed the following comments from Dave Martin and Nicolas Pitre:
	- Fixed help text for EXYNOS5420_MCPM symbol.
	- Removed mcpm-exynos-setup.S file and added similar code from tc2_pm.c.
	- Changed the spinlock name from "bl_lock" to "exynos_mcpm_lock".
	- Removed snoop enable/disable calls due to possible cpuidle issue and
	  not having numbers proving a significant power savings. Dropped the
	  "drivers/bus: arm-cci: Add common control interface for ACE ports"
	  patch from v1 as it was no longer needed.
	- Created a macro for exynos-specific v7_exit_coherency_flush which
	  handles an erratum. This was done to prevent duplication of code.
	- Removed "outer_flush_all" call.
	- Removed redundant dsb in power_down function.
	- Removed unnecessary initialization of global variables to zero.
	- Split the /dev/bL_status debug interface into another patch.
	- Fixed error handling in exynos_mcpm_init().
	- Called mcpm_smp_set_ops directly from exynos_mcpm_init().
	- Added a TODO for supporting cluster down on exynos5420.

NOTE:
- Have added Leela Krishna's generic cpu power control function series
  as part of this patchset.
- There is no change in the patch "ARM: dts: exynos5420: add CCI node"
  and "arm: exynos: Add /dev/bL_status user interface on Exynos5420"
  from v2.
- I have tested with and without the erratum 799270 workaround and both
  work fine. I have kept the erratum fix for the time being.

Abhilash Kesavan (3):
  arm: exynos: Add generic cluster power control functions
  arm: exynos: Add MCPM call-back functions
  arm: exynos: Add /dev/bL_status user interface on Exynos5420

Andrew Bresticker (1):
  ARM: dts: exynos5420: add CCI node

Leela Krishna Amudala (2):
  ARM: EXYNOS: Add generic cpu power control functions for all exynos
    based SoCs
  ARM: EXYNOS: use generic exynos cpu power control functions

 arch/arm/boot/dts/exynos5420.dtsi  |  27 +++
 arch/arm/mach-exynos/Kconfig       |   8 +
 arch/arm/mach-exynos/Makefile      |   2 +
 arch/arm/mach-exynos/common.h      |   6 +
 arch/arm/mach-exynos/mcpm-exynos.c | 385 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/platsmp.c     |   9 +-
 arch/arm/mach-exynos/pm.c          |  66 +++++++
 arch/arm/mach-exynos/regs-pmu.h    |  15 ++
 8 files changed, 512 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

-- 
1.8.3.2

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

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

* [PATCH v3 0/6] MCPM backend for Exynos5420
@ 2014-04-26 16:05 ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

This is v3 of the series adding MCPM backend support for SMP secondary boot
and core switching on Samsung's Exynos5420. The patches are based on the mcpm
support added for Exynos5420 in the Chromium kernel repository here:
https://chromium.googlesource.com/chromiumos/third_party/kernel-next/+/chromeos-3.8

This patchset depends on:
- ARM: EXYNOS: Map SYSRAM address through DT
(http://www.spinics.net/lists/arm-kernel/msg323011.html)

The patches have been prepared on linux-next(20140424) and tested on SMDK5420
EVT1 using the "/dev/b.L_switcher" user interface. Secondary core bring-up has
also been tested on an Exynos5420-based chromebook.

Changes since v2:
Addressed the following comments from Nicolas Pitre and Daniel Lezcano
	- Added generic common (cluster) configuration functions to pm.c
	  which may be used by other subsystems.
	- Removed unused "cpumask" variable in mcpm code.
	- Re-worked exynos_power_down_finish() referencing the tc2_pm code.
	- Removed the status checks in core and cluster power functions. We
	  just set the power control bit and do not check the previous state
	  anymore.
	- Removed incorrect jiffies timeout usage in path where IRQs are
	  disabled.

Changes since v1:
Addressed the following comments from Dave Martin and Nicolas Pitre:
	- Fixed help text for EXYNOS5420_MCPM symbol.
	- Removed mcpm-exynos-setup.S file and added similar code from tc2_pm.c.
	- Changed the spinlock name from "bl_lock" to "exynos_mcpm_lock".
	- Removed snoop enable/disable calls due to possible cpuidle issue and
	  not having numbers proving a significant power savings. Dropped the
	  "drivers/bus: arm-cci: Add common control interface for ACE ports"
	  patch from v1 as it was no longer needed.
	- Created a macro for exynos-specific v7_exit_coherency_flush which
	  handles an erratum. This was done to prevent duplication of code.
	- Removed "outer_flush_all" call.
	- Removed redundant dsb in power_down function.
	- Removed unnecessary initialization of global variables to zero.
	- Split the /dev/bL_status debug interface into another patch.
	- Fixed error handling in exynos_mcpm_init().
	- Called mcpm_smp_set_ops directly from exynos_mcpm_init().
	- Added a TODO for supporting cluster down on exynos5420.

NOTE:
- Have added Leela Krishna's generic cpu power control function series
  as part of this patchset.
- There is no change in the patch "ARM: dts: exynos5420: add CCI node"
  and "arm: exynos: Add /dev/bL_status user interface on Exynos5420"
  from v2.
- I have tested with and without the erratum 799270 workaround and both
  work fine. I have kept the erratum fix for the time being.

Abhilash Kesavan (3):
  arm: exynos: Add generic cluster power control functions
  arm: exynos: Add MCPM call-back functions
  arm: exynos: Add /dev/bL_status user interface on Exynos5420

Andrew Bresticker (1):
  ARM: dts: exynos5420: add CCI node

Leela Krishna Amudala (2):
  ARM: EXYNOS: Add generic cpu power control functions for all exynos
    based SoCs
  ARM: EXYNOS: use generic exynos cpu power control functions

 arch/arm/boot/dts/exynos5420.dtsi  |  27 +++
 arch/arm/mach-exynos/Kconfig       |   8 +
 arch/arm/mach-exynos/Makefile      |   2 +
 arch/arm/mach-exynos/common.h      |   6 +
 arch/arm/mach-exynos/mcpm-exynos.c | 385 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/platsmp.c     |   9 +-
 arch/arm/mach-exynos/pm.c          |  66 +++++++
 arch/arm/mach-exynos/regs-pmu.h    |  15 ++
 8 files changed, 512 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

-- 
1.8.3.2

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

* [PATCH v3 1/6] ARM: EXYNOS: Add generic cpu power control functions for all exynos based SoCs
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-04-26 16:05     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

From: Leela Krishna Amudala <leela.krishna-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Add generic cpu power control functions for exynos based SoCS
for cpu power up/down and to know the cpu status.

Signed-off-by: Leela Krishna Amudala <leela.krishna-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 arch/arm/mach-exynos/common.h   |  3 +++
 arch/arm/mach-exynos/pm.c       | 36 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |  6 ++++++
 3 files changed, 45 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 88c619d..dc6b9a6 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -61,5 +61,8 @@ struct exynos_pmu_conf {
 };
 
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+extern void exynos_cpu_powerdown(int cpu);
+extern void exynos_cpu_powerup(int cpu);
+extern int  exynos_cpu_power_state(int cpu);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 15af0ce..6651028 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -100,6 +100,42 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 	return -ENOENT;
 }
 
+/**
+ * exynos_cpu_powerdown : power down the specified cpu
+ * @cpu : the cpu to power down
+ *
+ * Power downs the specified cpu. The sequence must be finished by a
+ * call to cpu_do_idle()
+ *
+ */
+void exynos_cpu_powerdown(int cpu)
+{
+	__raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+}
+
+/**
+ * exynos_cpu_powerup : power up the specified cpu
+ * @cpu : the cpu to power up
+ *
+ * Power up the specified cpu
+ */
+void exynos_cpu_powerup(int cpu)
+{
+	__raw_writel(S5P_CORE_LOCAL_PWR_EN,
+		     EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+}
+
+/**
+ * exynos_cpu_power_state : returns the power state of the cpu
+ * @cpu : the cpu to retrieve the power state from
+ *
+ */
+int exynos_cpu_power_state(int cpu)
+{
+	return (__raw_readl(EXYNOS_ARM_CORE_STATUS(cpu)) &
+			S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 4f6a256..0bdfcbc 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -121,6 +121,12 @@
 
 #define S5P_CHECK_SLEEP				0x00000BAD
 
+#define EXYNOS_ARM_CORE0_CONFIGURATION		S5P_PMUREG(0x2000)
+#define EXYNOS_ARM_CORE_CONFIGURATION(_nr)	\
+			(EXYNOS_ARM_CORE0_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_ARM_CORE_STATUS(_nr)		\
+			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
+
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154)
 #define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174)
-- 
1.8.3.2

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

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

* [PATCH v3 1/6] ARM: EXYNOS: Add generic cpu power control functions for all exynos based SoCs
@ 2014-04-26 16:05     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Leela Krishna Amudala <leela.krishna@linaro.org>

Add generic cpu power control functions for exynos based SoCS
for cpu power up/down and to know the cpu status.

Signed-off-by: Leela Krishna Amudala <leela.krishna@linaro.org>
---
 arch/arm/mach-exynos/common.h   |  3 +++
 arch/arm/mach-exynos/pm.c       | 36 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |  6 ++++++
 3 files changed, 45 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 88c619d..dc6b9a6 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -61,5 +61,8 @@ struct exynos_pmu_conf {
 };
 
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+extern void exynos_cpu_powerdown(int cpu);
+extern void exynos_cpu_powerup(int cpu);
+extern int  exynos_cpu_power_state(int cpu);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 15af0ce..6651028 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -100,6 +100,42 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 	return -ENOENT;
 }
 
+/**
+ * exynos_cpu_powerdown : power down the specified cpu
+ * @cpu : the cpu to power down
+ *
+ * Power downs the specified cpu. The sequence must be finished by a
+ * call to cpu_do_idle()
+ *
+ */
+void exynos_cpu_powerdown(int cpu)
+{
+	__raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+}
+
+/**
+ * exynos_cpu_powerup : power up the specified cpu
+ * @cpu : the cpu to power up
+ *
+ * Power up the specified cpu
+ */
+void exynos_cpu_powerup(int cpu)
+{
+	__raw_writel(S5P_CORE_LOCAL_PWR_EN,
+		     EXYNOS_ARM_CORE_CONFIGURATION(cpu));
+}
+
+/**
+ * exynos_cpu_power_state : returns the power state of the cpu
+ * @cpu : the cpu to retrieve the power state from
+ *
+ */
+int exynos_cpu_power_state(int cpu)
+{
+	return (__raw_readl(EXYNOS_ARM_CORE_STATUS(cpu)) &
+			S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 4f6a256..0bdfcbc 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -121,6 +121,12 @@
 
 #define S5P_CHECK_SLEEP				0x00000BAD
 
+#define EXYNOS_ARM_CORE0_CONFIGURATION		S5P_PMUREG(0x2000)
+#define EXYNOS_ARM_CORE_CONFIGURATION(_nr)	\
+			(EXYNOS_ARM_CORE0_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_ARM_CORE_STATUS(_nr)		\
+			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
+
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154)
 #define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174)
-- 
1.8.3.2

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

* [PATCH v3 2/6] ARM: EXYNOS: use generic exynos cpu power control functions
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-04-26 16:05     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

From: Leela Krishna Amudala <leela.krishna-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Use generic exynos cpu power control functions to power up/down
and to know the status of the cpu.

Signed-off-by: Leela Krishna Amudala <leela.krishna-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 arch/arm/mach-exynos/platsmp.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 03e5e9f..e3d005b 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -107,15 +107,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 */
 	write_pen_release(phys_cpu);
 
-	if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
-		__raw_writel(S5P_CORE_LOCAL_PWR_EN,
-			     S5P_ARM_CORE1_CONFIGURATION);
-
+	if (!exynos_cpu_power_state(cpu)) {
+		exynos_cpu_powerup(cpu);
 		timeout = 10;
 
 		/* wait max 10 ms until cpu1 is on */
-		while ((__raw_readl(S5P_ARM_CORE1_STATUS)
-			& S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
+		while (exynos_cpu_power_state(cpu) != S5P_CORE_LOCAL_PWR_EN) {
 			if (timeout-- == 0)
 				break;
 
-- 
1.8.3.2

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

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

* [PATCH v3 2/6] ARM: EXYNOS: use generic exynos cpu power control functions
@ 2014-04-26 16:05     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Leela Krishna Amudala <leela.krishna@linaro.org>

Use generic exynos cpu power control functions to power up/down
and to know the status of the cpu.

Signed-off-by: Leela Krishna Amudala <leela.krishna@linaro.org>
---
 arch/arm/mach-exynos/platsmp.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 03e5e9f..e3d005b 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -107,15 +107,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 */
 	write_pen_release(phys_cpu);
 
-	if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
-		__raw_writel(S5P_CORE_LOCAL_PWR_EN,
-			     S5P_ARM_CORE1_CONFIGURATION);
-
+	if (!exynos_cpu_power_state(cpu)) {
+		exynos_cpu_powerup(cpu);
 		timeout = 10;
 
 		/* wait max 10 ms until cpu1 is on */
-		while ((__raw_readl(S5P_ARM_CORE1_STATUS)
-			& S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
+		while (exynos_cpu_power_state(cpu) != S5P_CORE_LOCAL_PWR_EN) {
 			if (timeout-- == 0)
 				break;
 
-- 
1.8.3.2

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

* [PATCH v3 3/6] arm: exynos: Add generic cluster power control functions
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-04-26 16:05     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

Add generic cluster power control functions for exynos based SoCS
for cluster power up/down and to know the cluster status.

Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/mach-exynos/common.h   |  3 +++
 arch/arm/mach-exynos/pm.c       | 30 ++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |  6 ++++++
 3 files changed, 39 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index dc6b9a6..af99b4a 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -64,5 +64,8 @@ extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
 extern void exynos_cpu_powerdown(int cpu);
 extern void exynos_cpu_powerup(int cpu);
 extern int  exynos_cpu_power_state(int cpu);
+extern void exynos_cluster_powerdown(int cluster);
+extern void exynos_cluster_powerup(int cluster);
+extern int  exynos_cluster_power_state(int cluster);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 6651028..f02d864 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -136,6 +136,36 @@ int exynos_cpu_power_state(int cpu)
 			S5P_CORE_LOCAL_PWR_EN);
 }
 
+/**
+ * exynos_common_powerdown : power down the specified cluster
+ * @cluster : the cluster to power down
+ */
+void exynos_cluster_powerdown(int cluster)
+{
+	__raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_powerup : power up the specified cluster
+ * @cluster : the cluster to power up
+ */
+void exynos_cluster_powerup(int cluster)
+{
+	__raw_writel(S5P_CORE_LOCAL_PWR_EN,
+		     EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_power_state : returns the power state of the cluster
+ * @cluster : the cluster to retrieve the power state from
+ *
+ */
+int exynos_cluster_power_state(int cluster)
+{
+	return (__raw_readl(EXYNOS_COMMON_STATUS(cluster)) &
+			S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 0bdfcbc..6685ebf 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -127,6 +127,12 @@
 #define EXYNOS_ARM_CORE_STATUS(_nr)		\
 			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
 
+#define EXYNOS_ARM_COMMON_CONFIGURATION		S5P_PMUREG(0x2500)
+#define EXYNOS_COMMON_CONFIGURATION(_nr)	\
+			(EXYNOS_ARM_COMMON_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_COMMON_STATUS(_nr)		\
+			(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x4)
+
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154)
 #define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174)
-- 
1.8.3.2

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

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

* [PATCH v3 3/6] arm: exynos: Add generic cluster power control functions
@ 2014-04-26 16:05     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

Add generic cluster power control functions for exynos based SoCS
for cluster power up/down and to know the cluster status.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/mach-exynos/common.h   |  3 +++
 arch/arm/mach-exynos/pm.c       | 30 ++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |  6 ++++++
 3 files changed, 39 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index dc6b9a6..af99b4a 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -64,5 +64,8 @@ extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
 extern void exynos_cpu_powerdown(int cpu);
 extern void exynos_cpu_powerup(int cpu);
 extern int  exynos_cpu_power_state(int cpu);
+extern void exynos_cluster_powerdown(int cluster);
+extern void exynos_cluster_powerup(int cluster);
+extern int  exynos_cluster_power_state(int cluster);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 6651028..f02d864 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -136,6 +136,36 @@ int exynos_cpu_power_state(int cpu)
 			S5P_CORE_LOCAL_PWR_EN);
 }
 
+/**
+ * exynos_common_powerdown : power down the specified cluster
+ * @cluster : the cluster to power down
+ */
+void exynos_cluster_powerdown(int cluster)
+{
+	__raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_powerup : power up the specified cluster
+ * @cluster : the cluster to power up
+ */
+void exynos_cluster_powerup(int cluster)
+{
+	__raw_writel(S5P_CORE_LOCAL_PWR_EN,
+		     EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_power_state : returns the power state of the cluster
+ * @cluster : the cluster to retrieve the power state from
+ *
+ */
+int exynos_cluster_power_state(int cluster)
+{
+	return (__raw_readl(EXYNOS_COMMON_STATUS(cluster)) &
+			S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 0bdfcbc..6685ebf 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -127,6 +127,12 @@
 #define EXYNOS_ARM_CORE_STATUS(_nr)		\
 			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
 
+#define EXYNOS_ARM_COMMON_CONFIGURATION		S5P_PMUREG(0x2500)
+#define EXYNOS_COMMON_CONFIGURATION(_nr)	\
+			(EXYNOS_ARM_COMMON_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_COMMON_STATUS(_nr)		\
+			(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x4)
+
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154)
 #define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174)
-- 
1.8.3.2

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

* [PATCH v3 4/6] ARM: dts: exynos5420: add CCI node
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-04-26 16:05     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

From: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Add device-tree bindings for the ARM CCI-400 on Exynos5420.  There
are two slave interfaces: one for the A15 cluster and one for the
A7 cluster.

Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/boot/dts/exynos5420.dtsi | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 217376f..43e7b25 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -58,6 +58,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x0>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu1: cpu@1 {
@@ -65,6 +66,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x1>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu2: cpu@2 {
@@ -72,6 +74,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x2>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu3: cpu@3 {
@@ -79,6 +82,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x3>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu4: cpu@100 {
@@ -86,6 +90,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x100>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu5: cpu@101 {
@@ -93,6 +98,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x101>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu6: cpu@102 {
@@ -100,6 +106,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x102>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu7: cpu@103 {
@@ -107,6 +114,26 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x103>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
+		};
+	};
+
+	cci@10d20000 {
+		compatible = "arm,cci-400";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x10d20000 0x1000>;
+		ranges = <0x0 0x10d20000 0x6000>;
+
+		cci_control0: slave-if@4000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x4000 0x1000>;
+		};
+		cci_control1: slave-if@5000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x5000 0x1000>;
 		};
 	};
 
-- 
1.8.3.2

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

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

* [PATCH v3 4/6] ARM: dts: exynos5420: add CCI node
@ 2014-04-26 16:05     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Andrew Bresticker <abrestic@chromium.org>

Add device-tree bindings for the ARM CCI-400 on Exynos5420.  There
are two slave interfaces: one for the A15 cluster and one for the
A7 cluster.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/boot/dts/exynos5420.dtsi | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 217376f..43e7b25 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -58,6 +58,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x0>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu1: cpu at 1 {
@@ -65,6 +66,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x1>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu2: cpu at 2 {
@@ -72,6 +74,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x2>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu3: cpu at 3 {
@@ -79,6 +82,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x3>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu4: cpu at 100 {
@@ -86,6 +90,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x100>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu5: cpu at 101 {
@@ -93,6 +98,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x101>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu6: cpu at 102 {
@@ -100,6 +106,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x102>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu7: cpu at 103 {
@@ -107,6 +114,26 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x103>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
+		};
+	};
+
+	cci at 10d20000 {
+		compatible = "arm,cci-400";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x10d20000 0x1000>;
+		ranges = <0x0 0x10d20000 0x6000>;
+
+		cci_control0: slave-if at 4000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x4000 0x1000>;
+		};
+		cci_control1: slave-if at 5000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x5000 0x1000>;
 		};
 	};
 
-- 
1.8.3.2

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-04-26 16:05     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

Add machine-dependent MCPM call-backs for Exynos5420. These are used
to power up/down the secondary CPUs during boot, shutdown, s2r and
switching.

Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/mach-exynos/Kconfig       |   8 +
 arch/arm/mach-exynos/Makefile      |   2 +
 arch/arm/mach-exynos/mcpm-exynos.c | 321 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h    |   3 +
 4 files changed, 334 insertions(+)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index fc8bf18..1602abc 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -110,4 +110,12 @@ config SOC_EXYNOS5440
 
 endmenu
 
+config EXYNOS5420_MCPM
+	bool "Exynos5420 Multi-Cluster PM support"
+	depends on MCPM && SOC_EXYNOS5420
+	select ARM_CCI
+	help
+	  This is needed to provide CPU and cluster power management
+	  on Exynos5420 implementing big.LITTLE.
+
 endif
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index a656dbe..01bc9b9 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= firmware.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec)
+
+obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
new file mode 100644
index 0000000..f9977bf
--- /dev/null
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * arch/arm/mach-exynos/mcpm-exynos.c
+ *
+ * Based on arch/arm/mach-vexpress/dcscb.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/arm-cci.h>
+
+#include <asm/mcpm.h>
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+
+#include <plat/cpu.h>
+
+#include "regs-pmu.h"
+#include "common.h"
+
+#define EXYNOS5420_CPUS_PER_CLUSTER	4
+#define EXYNOS5420_NR_CLUSTERS		2
+
+/* Secondary CPU entry point */
+#define REG_ENTRY_ADDR		(S5P_VA_SYSRAM_NS + 0x1C)
+
+/*
+ * The common v7_exit_coherency_flush API could not be used because of the
+ * Erratum 799270 workaround. This macro is the same as the common one (in
+ * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
+ */
+#define exynos_v7_exit_coherency_flush(level) \
+	asm volatile( \
+	"stmfd	sp!, {fp, ip}\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \
+	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \
+	"isb\n\t"\
+	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \
+	"clrex\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \
+	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \
+	/* Dummy Load of a device register to avoid Erratum 799270 */ \
+	"ldr	r4, [%0]\n\t" \
+	"and	r4, r4, #0\n\t" \
+	"orr	r0, r0, r4\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \
+	"isb\n\t" \
+	"dsb\n\t" \
+	"ldmfd	sp!, {fp, ip}" \
+	: \
+	: "Ir" (S5P_INFORM0) \
+	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+	  "r9", "r10", "lr", "memory")
+
+/*
+ * We can't use regular spinlocks. In the switcher case, it is possible
+ * for an outbound CPU to call power_down() after its inbound counterpart
+ * is already live using the same logical CPU number which trips lockdep
+ * debugging.
+ */
+static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+static int
+cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
+
+static int exynos_cluster_power_control(unsigned int cluster, int enable)
+{
+	unsigned int tries = 100;
+	unsigned int val = 0;
+
+	if (enable) {
+		exynos_cluster_powerup(cluster);
+		val = S5P_CORE_LOCAL_PWR_EN;
+	} else {
+		exynos_cluster_powerdown(cluster);
+	}
+
+	/* Wait until cluster power control is applied */
+	while (tries--) {
+		if (exynos_cluster_power_state(cluster) == val)
+			return 0;
+
+		cpu_relax();
+	}
+	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
+		enable ? "on" : "off");
+
+	return -ETIMEDOUT;
+}
+
+static int exynos_power_up(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+	unsigned int err;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+		cluster >= EXYNOS5420_NR_CLUSTERS)
+		return -EINVAL;
+
+	/*
+	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
+	 * variant exists, we need to disable IRQs manually here.
+	 */
+	local_irq_disable();
+	arch_spin_lock(&exynos_mcpm_lock);
+
+	cpu_use_count[cpu][cluster]++;
+	if (cpu_use_count[cpu][cluster] == 1) {
+		bool was_cluster_down =
+			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;
+
+		/*
+		 * Turn on the cluster (L2/COMMON) and then power on the cores.
+		 * TODO: Turn off the clusters when all cores in the cluster
+		 * are down to achieve significant power savings.
+		 */
+		if (was_cluster_down) {
+			err = exynos_cluster_power_control(cluster, 1);
+			if (err) {
+				exynos_cluster_power_control(cluster, 0);
+				return err;
+			}
+		}
+
+		exynos_cpu_powerup(cpunr);
+
+		/* CPU should be powered up there */
+		/* Also setup Cluster Power Sequence here */
+	} else if (cpu_use_count[cpu][cluster] != 2) {
+		/*
+		 * The only possible values are:
+		 * 0 = CPU down
+		 * 1 = CPU (still) up
+		 * 2 = CPU requested to be up before it had a chance
+		 *     to actually make itself down.
+		 * Any other value is a bug.
+		 */
+		BUG();
+	}
+
+	arch_spin_unlock(&exynos_mcpm_lock);
+	local_irq_enable();
+
+	return 0;
+}
+
+static void exynos_power_down(void)
+{
+	unsigned int mpidr, cpu, cluster;
+	bool last_man = false, skip_wfi = false;
+	unsigned int cpunr;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	__mcpm_cpu_going_down(cpu, cluster);
+
+	arch_spin_lock(&exynos_mcpm_lock);
+	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+	cpu_use_count[cpu][cluster]--;
+	if (cpu_use_count[cpu][cluster] == 0) {
+		int cnt = 0, i;
+
+		exynos_cpu_powerdown(cpunr);
+		for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
+			cnt += cpu_use_count[i][cluster];
+		if (cnt == 0)
+			last_man = true;
+	} else if (cpu_use_count[cpu][cluster] == 1) {
+		/*
+		 * A power_up request went ahead of us.
+		 * Even if we do not want to shut this CPU down,
+		 * the caller expects a certain state as if the WFI
+		 * was aborted.  So let's continue with cache cleaning.
+		 */
+		skip_wfi = true;
+	} else {
+		BUG();
+	}
+
+	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		/* Flush all cache levels for this cluster. */
+		exynos_v7_exit_coherency_flush(all);
+
+		/*
+		 * Disable cluster-level coherency by masking
+		 * incoming snoops and DVM messages:
+		 */
+		cci_disable_port_by_cpu(mpidr);
+
+		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
+	} else {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		/* Disable and flush the local CPU cache. */
+		exynos_v7_exit_coherency_flush(louis);
+	}
+
+	__mcpm_cpu_down(cpu, cluster);
+
+	/* Now we are prepared for power-down, do it: */
+	if (!skip_wfi)
+		wfi();
+
+	/* Not dead at this point?  Let our caller cope. */
+}
+
+static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int tries = 100;
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	/* Wait for the core state to be OFF */
+	while (tries--) {
+		if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
+			if ((exynos_cpu_power_state(cpunr) == 0))
+				return 0; /* success: the CPU is halted */
+		}
+
+		/* Otherwise, wait and retry: */
+		msleep(1);
+	}
+
+	return -ETIMEDOUT; /* timeout */
+}
+
+static const struct mcpm_platform_ops exynos_power_ops = {
+	.power_up		= exynos_power_up,
+	.power_down		= exynos_power_down,
+	.power_down_finish	= exynos_power_down_finish,
+};
+
+static void __init exynos_mcpm_usage_count_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	cpu_use_count[cpu][cluster] = 1;
+}
+
+/*
+ * Enable cluster-level coherency, in preparation for turning on the MMU.
+ */
+static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
+{
+	asm volatile ("\n"
+	"cmp	r0, #1\n"
+	"bxne	lr\n"
+	"b	cci_enable_port_for_self");
+}
+
+static int __init exynos_mcpm_init(void)
+{
+	int ret = 0;
+
+	if (!soc_is_exynos5420())
+		return -ENODEV;
+
+	if (!cci_probed())
+		return -ENODEV;
+
+	/*
+	 * To increase the stability of KFC reset we need to program
+	 * the PMU SPARE3 register
+	 */
+	__raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
+
+	exynos_mcpm_usage_count_init();
+
+	ret = mcpm_platform_register(&exynos_power_ops);
+	if (!ret)
+		ret = mcpm_sync_init(exynos_pm_power_up_setup);
+	if (ret)
+		return ret;
+
+	mcpm_smp_set_ops();
+
+	pr_info("Exynos MCPM support installed\n");
+
+	/*
+	 * Future entries into the kernel can now go
+	 * through the cluster entry vectors.
+	 */
+	__raw_writel(virt_to_phys(mcpm_entry_point),
+		REG_ENTRY_ADDR);
+
+	return ret;
+}
+
+early_initcall(exynos_mcpm_init);
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 6685ebf..f44d318 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -38,6 +38,7 @@
 #define S5P_INFORM5				S5P_PMUREG(0x0814)
 #define S5P_INFORM6				S5P_PMUREG(0x0818)
 #define S5P_INFORM7				S5P_PMUREG(0x081C)
+#define S5P_PMU_SPARE3				S5P_PMUREG(0x090C)
 
 #define S5P_ARM_CORE0_LOWPWR			S5P_PMUREG(0x1000)
 #define S5P_DIS_IRQ_CORE0			S5P_PMUREG(0x1004)
@@ -325,4 +326,6 @@
 
 #define EXYNOS5_OPTION_USE_RETENTION				(1 << 4)
 
+#define EXYNOS5420_SWRESET_KFC_SEL				0x3
+
 #endif /* __ASM_ARCH_REGS_PMU_H */
-- 
1.8.3.2

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

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-26 16:05     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

Add machine-dependent MCPM call-backs for Exynos5420. These are used
to power up/down the secondary CPUs during boot, shutdown, s2r and
switching.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/mach-exynos/Kconfig       |   8 +
 arch/arm/mach-exynos/Makefile      |   2 +
 arch/arm/mach-exynos/mcpm-exynos.c | 321 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h    |   3 +
 4 files changed, 334 insertions(+)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index fc8bf18..1602abc 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -110,4 +110,12 @@ config SOC_EXYNOS5440
 
 endmenu
 
+config EXYNOS5420_MCPM
+	bool "Exynos5420 Multi-Cluster PM support"
+	depends on MCPM && SOC_EXYNOS5420
+	select ARM_CCI
+	help
+	  This is needed to provide CPU and cluster power management
+	  on Exynos5420 implementing big.LITTLE.
+
 endif
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index a656dbe..01bc9b9 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= firmware.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec)
+
+obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
new file mode 100644
index 0000000..f9977bf
--- /dev/null
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * arch/arm/mach-exynos/mcpm-exynos.c
+ *
+ * Based on arch/arm/mach-vexpress/dcscb.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/arm-cci.h>
+
+#include <asm/mcpm.h>
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+
+#include <plat/cpu.h>
+
+#include "regs-pmu.h"
+#include "common.h"
+
+#define EXYNOS5420_CPUS_PER_CLUSTER	4
+#define EXYNOS5420_NR_CLUSTERS		2
+
+/* Secondary CPU entry point */
+#define REG_ENTRY_ADDR		(S5P_VA_SYSRAM_NS + 0x1C)
+
+/*
+ * The common v7_exit_coherency_flush API could not be used because of the
+ * Erratum 799270 workaround. This macro is the same as the common one (in
+ * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
+ */
+#define exynos_v7_exit_coherency_flush(level) \
+	asm volatile( \
+	"stmfd	sp!, {fp, ip}\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \
+	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \
+	"isb\n\t"\
+	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \
+	"clrex\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \
+	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \
+	/* Dummy Load of a device register to avoid Erratum 799270 */ \
+	"ldr	r4, [%0]\n\t" \
+	"and	r4, r4, #0\n\t" \
+	"orr	r0, r0, r4\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \
+	"isb\n\t" \
+	"dsb\n\t" \
+	"ldmfd	sp!, {fp, ip}" \
+	: \
+	: "Ir" (S5P_INFORM0) \
+	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+	  "r9", "r10", "lr", "memory")
+
+/*
+ * We can't use regular spinlocks. In the switcher case, it is possible
+ * for an outbound CPU to call power_down() after its inbound counterpart
+ * is already live using the same logical CPU number which trips lockdep
+ * debugging.
+ */
+static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+static int
+cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
+
+static int exynos_cluster_power_control(unsigned int cluster, int enable)
+{
+	unsigned int tries = 100;
+	unsigned int val = 0;
+
+	if (enable) {
+		exynos_cluster_powerup(cluster);
+		val = S5P_CORE_LOCAL_PWR_EN;
+	} else {
+		exynos_cluster_powerdown(cluster);
+	}
+
+	/* Wait until cluster power control is applied */
+	while (tries--) {
+		if (exynos_cluster_power_state(cluster) == val)
+			return 0;
+
+		cpu_relax();
+	}
+	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
+		enable ? "on" : "off");
+
+	return -ETIMEDOUT;
+}
+
+static int exynos_power_up(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+	unsigned int err;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+		cluster >= EXYNOS5420_NR_CLUSTERS)
+		return -EINVAL;
+
+	/*
+	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
+	 * variant exists, we need to disable IRQs manually here.
+	 */
+	local_irq_disable();
+	arch_spin_lock(&exynos_mcpm_lock);
+
+	cpu_use_count[cpu][cluster]++;
+	if (cpu_use_count[cpu][cluster] == 1) {
+		bool was_cluster_down =
+			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;
+
+		/*
+		 * Turn on the cluster (L2/COMMON) and then power on the cores.
+		 * TODO: Turn off the clusters when all cores in the cluster
+		 * are down to achieve significant power savings.
+		 */
+		if (was_cluster_down) {
+			err = exynos_cluster_power_control(cluster, 1);
+			if (err) {
+				exynos_cluster_power_control(cluster, 0);
+				return err;
+			}
+		}
+
+		exynos_cpu_powerup(cpunr);
+
+		/* CPU should be powered up there */
+		/* Also setup Cluster Power Sequence here */
+	} else if (cpu_use_count[cpu][cluster] != 2) {
+		/*
+		 * The only possible values are:
+		 * 0 = CPU down
+		 * 1 = CPU (still) up
+		 * 2 = CPU requested to be up before it had a chance
+		 *     to actually make itself down.
+		 * Any other value is a bug.
+		 */
+		BUG();
+	}
+
+	arch_spin_unlock(&exynos_mcpm_lock);
+	local_irq_enable();
+
+	return 0;
+}
+
+static void exynos_power_down(void)
+{
+	unsigned int mpidr, cpu, cluster;
+	bool last_man = false, skip_wfi = false;
+	unsigned int cpunr;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	__mcpm_cpu_going_down(cpu, cluster);
+
+	arch_spin_lock(&exynos_mcpm_lock);
+	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+	cpu_use_count[cpu][cluster]--;
+	if (cpu_use_count[cpu][cluster] == 0) {
+		int cnt = 0, i;
+
+		exynos_cpu_powerdown(cpunr);
+		for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
+			cnt += cpu_use_count[i][cluster];
+		if (cnt == 0)
+			last_man = true;
+	} else if (cpu_use_count[cpu][cluster] == 1) {
+		/*
+		 * A power_up request went ahead of us.
+		 * Even if we do not want to shut this CPU down,
+		 * the caller expects a certain state as if the WFI
+		 * was aborted.  So let's continue with cache cleaning.
+		 */
+		skip_wfi = true;
+	} else {
+		BUG();
+	}
+
+	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		/* Flush all cache levels for this cluster. */
+		exynos_v7_exit_coherency_flush(all);
+
+		/*
+		 * Disable cluster-level coherency by masking
+		 * incoming snoops and DVM messages:
+		 */
+		cci_disable_port_by_cpu(mpidr);
+
+		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
+	} else {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		/* Disable and flush the local CPU cache. */
+		exynos_v7_exit_coherency_flush(louis);
+	}
+
+	__mcpm_cpu_down(cpu, cluster);
+
+	/* Now we are prepared for power-down, do it: */
+	if (!skip_wfi)
+		wfi();
+
+	/* Not dead@this point?  Let our caller cope. */
+}
+
+static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int tries = 100;
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	/* Wait for the core state to be OFF */
+	while (tries--) {
+		if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
+			if ((exynos_cpu_power_state(cpunr) == 0))
+				return 0; /* success: the CPU is halted */
+		}
+
+		/* Otherwise, wait and retry: */
+		msleep(1);
+	}
+
+	return -ETIMEDOUT; /* timeout */
+}
+
+static const struct mcpm_platform_ops exynos_power_ops = {
+	.power_up		= exynos_power_up,
+	.power_down		= exynos_power_down,
+	.power_down_finish	= exynos_power_down_finish,
+};
+
+static void __init exynos_mcpm_usage_count_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	cpu_use_count[cpu][cluster] = 1;
+}
+
+/*
+ * Enable cluster-level coherency, in preparation for turning on the MMU.
+ */
+static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
+{
+	asm volatile ("\n"
+	"cmp	r0, #1\n"
+	"bxne	lr\n"
+	"b	cci_enable_port_for_self");
+}
+
+static int __init exynos_mcpm_init(void)
+{
+	int ret = 0;
+
+	if (!soc_is_exynos5420())
+		return -ENODEV;
+
+	if (!cci_probed())
+		return -ENODEV;
+
+	/*
+	 * To increase the stability of KFC reset we need to program
+	 * the PMU SPARE3 register
+	 */
+	__raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
+
+	exynos_mcpm_usage_count_init();
+
+	ret = mcpm_platform_register(&exynos_power_ops);
+	if (!ret)
+		ret = mcpm_sync_init(exynos_pm_power_up_setup);
+	if (ret)
+		return ret;
+
+	mcpm_smp_set_ops();
+
+	pr_info("Exynos MCPM support installed\n");
+
+	/*
+	 * Future entries into the kernel can now go
+	 * through the cluster entry vectors.
+	 */
+	__raw_writel(virt_to_phys(mcpm_entry_point),
+		REG_ENTRY_ADDR);
+
+	return ret;
+}
+
+early_initcall(exynos_mcpm_init);
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 6685ebf..f44d318 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -38,6 +38,7 @@
 #define S5P_INFORM5				S5P_PMUREG(0x0814)
 #define S5P_INFORM6				S5P_PMUREG(0x0818)
 #define S5P_INFORM7				S5P_PMUREG(0x081C)
+#define S5P_PMU_SPARE3				S5P_PMUREG(0x090C)
 
 #define S5P_ARM_CORE0_LOWPWR			S5P_PMUREG(0x1000)
 #define S5P_DIS_IRQ_CORE0			S5P_PMUREG(0x1004)
@@ -325,4 +326,6 @@
 
 #define EXYNOS5_OPTION_USE_RETENTION				(1 << 4)
 
+#define EXYNOS5420_SWRESET_KFC_SEL				0x3
+
 #endif /* __ASM_ARCH_REGS_PMU_H */
-- 
1.8.3.2

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

* [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-04-26 16:05     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

Add a user interface to check the core and cluster status on
Exynos5420. This can be utilized while debugging mcpm issues.
cat /dev/bL_status will show the current power status of all
the 8 cores along with the cluster.

Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/mach-exynos/mcpm-exynos.c | 64 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
index f9977bf..83428b0 100644
--- a/arch/arm/mach-exynos/mcpm-exynos.c
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -269,6 +269,53 @@ static void __init exynos_mcpm_usage_count_init(void)
 	cpu_use_count[cpu][cluster] = 1;
 }
 
+static size_t bL_check_status(char *info)
+{
+	size_t len = 0;
+	int i;
+
+	len += sprintf(&info[len], "\t0 1 2 3 L2\n");
+	len += sprintf(&info[len], "[A15]   ");
+	for (i = 0; i < 4; i++) {
+		len += sprintf(&info[len], "%d ",
+			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
+	}
+	len += sprintf(&info[len], "%d\n",
+			(readl(EXYNOS_COMMON_STATUS(0)) & 0x3) == 3 ? 1 : 0);
+
+	len += sprintf(&info[len], "[A7]    ");
+	for (i = 4; i < 8; i++)
+		len += sprintf(&info[len], "%d ",
+			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
+	len += sprintf(&info[len], "%d\n\n",
+			(readl(EXYNOS_COMMON_STATUS(1)) & 0x3) == 3 ? 1 : 0);
+
+	return len;
+}
+
+static ssize_t bL_status_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	size_t count = 0;
+	char info[100];
+
+	count = bL_check_status(info);
+	if (count < 0)
+		return -EINVAL;
+
+	return simple_read_from_buffer(buf, len, pos, info, count);
+}
+
+static const struct file_operations bL_status_fops = {
+	.read		= bL_status_read,
+};
+
+static struct miscdevice bL_status_device = {
+	MISC_DYNAMIC_MINOR,
+	"bL_status",
+	&bL_status_fops
+};
+
 /*
  * Enable cluster-level coherency, in preparation for turning on the MMU.
  */
@@ -319,3 +366,20 @@ static int __init exynos_mcpm_init(void)
 }
 
 early_initcall(exynos_mcpm_init);
+
+static int __init exynos_bl_status_init(void)
+{
+	int ret;
+
+	if (!soc_is_exynos5420())
+		return -ENODEV;
+
+	ret = misc_register(&bL_status_device);
+	if (ret) {
+		pr_info("bl_status not available\n");
+		return ret;
+	}
+	return 0;
+}
+
+late_initcall(exynos_bl_status_init);
-- 
1.8.3.2

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

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

* [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
@ 2014-04-26 16:05     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-26 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

Add a user interface to check the core and cluster status on
Exynos5420. This can be utilized while debugging mcpm issues.
cat /dev/bL_status will show the current power status of all
the 8 cores along with the cluster.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/mach-exynos/mcpm-exynos.c | 64 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
index f9977bf..83428b0 100644
--- a/arch/arm/mach-exynos/mcpm-exynos.c
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -269,6 +269,53 @@ static void __init exynos_mcpm_usage_count_init(void)
 	cpu_use_count[cpu][cluster] = 1;
 }
 
+static size_t bL_check_status(char *info)
+{
+	size_t len = 0;
+	int i;
+
+	len += sprintf(&info[len], "\t0 1 2 3 L2\n");
+	len += sprintf(&info[len], "[A15]   ");
+	for (i = 0; i < 4; i++) {
+		len += sprintf(&info[len], "%d ",
+			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
+	}
+	len += sprintf(&info[len], "%d\n",
+			(readl(EXYNOS_COMMON_STATUS(0)) & 0x3) == 3 ? 1 : 0);
+
+	len += sprintf(&info[len], "[A7]    ");
+	for (i = 4; i < 8; i++)
+		len += sprintf(&info[len], "%d ",
+			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
+	len += sprintf(&info[len], "%d\n\n",
+			(readl(EXYNOS_COMMON_STATUS(1)) & 0x3) == 3 ? 1 : 0);
+
+	return len;
+}
+
+static ssize_t bL_status_read(struct file *file, char __user *buf,
+			size_t len, loff_t *pos)
+{
+	size_t count = 0;
+	char info[100];
+
+	count = bL_check_status(info);
+	if (count < 0)
+		return -EINVAL;
+
+	return simple_read_from_buffer(buf, len, pos, info, count);
+}
+
+static const struct file_operations bL_status_fops = {
+	.read		= bL_status_read,
+};
+
+static struct miscdevice bL_status_device = {
+	MISC_DYNAMIC_MINOR,
+	"bL_status",
+	&bL_status_fops
+};
+
 /*
  * Enable cluster-level coherency, in preparation for turning on the MMU.
  */
@@ -319,3 +366,20 @@ static int __init exynos_mcpm_init(void)
 }
 
 early_initcall(exynos_mcpm_init);
+
+static int __init exynos_bl_status_init(void)
+{
+	int ret;
+
+	if (!soc_is_exynos5420())
+		return -ENODEV;
+
+	ret = misc_register(&bL_status_device);
+	if (ret) {
+		pr_info("bl_status not available\n");
+		return ret;
+	}
+	return 0;
+}
+
+late_initcall(exynos_bl_status_init);
-- 
1.8.3.2

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

* Re: [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-04-28 11:25         ` Daniel Lezcano
  -1 siblings, 0 replies; 60+ messages in thread
From: Daniel Lezcano @ 2014-04-28 11:25 UTC (permalink / raw)
  To: Abhilash Kesavan, nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A,
	Dave.Martin-5wv7dgnIgG8, lorenzo.pieralisi-5wv7dgnIgG8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
> Add a user interface to check the core and cluster status on
> Exynos5420. This can be utilized while debugging mcpm issues.
> cat /dev/bL_status will show the current power status of all
> the 8 cores along with the cluster.
>
> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---

Hi Abhilash,

I don't think you should add this file.

1. big Little is not exynos specific
2. /dev is not for the purpose of your patch

So I would recommend:

1. create a generic infra-structure for all the big.Little
2. and/or use debugfs

Furthermore, how is it usable ? Will you read the file every 2ms to 
check the cluster status, knowing it will be woken up by the read 
operation ?

Frankly speaking, it would make sense to add traces in mcpm.c (if they 
aren't already there - did not check).

>   arch/arm/mach-exynos/mcpm-exynos.c | 64 ++++++++++++++++++++++++++++++++++++++
>   1 file changed, 64 insertions(+)
>
> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
> index f9977bf..83428b0 100644
> --- a/arch/arm/mach-exynos/mcpm-exynos.c
> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
> @@ -269,6 +269,53 @@ static void __init exynos_mcpm_usage_count_init(void)
>   	cpu_use_count[cpu][cluster] = 1;
>   }
>
> +static size_t bL_check_status(char *info)
> +{
> +	size_t len = 0;
> +	int i;
> +
> +	len += sprintf(&info[len], "\t0 1 2 3 L2\n");
> +	len += sprintf(&info[len], "[A15]   ");
> +	for (i = 0; i < 4; i++) {
> +		len += sprintf(&info[len], "%d ",
> +			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
> +	}
> +	len += sprintf(&info[len], "%d\n",
> +			(readl(EXYNOS_COMMON_STATUS(0)) & 0x3) == 3 ? 1 : 0);
> +
> +	len += sprintf(&info[len], "[A7]    ");
> +	for (i = 4; i < 8; i++)
> +		len += sprintf(&info[len], "%d ",
> +			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
> +	len += sprintf(&info[len], "%d\n\n",
> +			(readl(EXYNOS_COMMON_STATUS(1)) & 0x3) == 3 ? 1 : 0);
> +
> +	return len;
> +}
> +
> +static ssize_t bL_status_read(struct file *file, char __user *buf,
> +			size_t len, loff_t *pos)
> +{
> +	size_t count = 0;
> +	char info[100];
> +
> +	count = bL_check_status(info);
> +	if (count < 0)
> +		return -EINVAL;
> +
> +	return simple_read_from_buffer(buf, len, pos, info, count);
> +}
> +
> +static const struct file_operations bL_status_fops = {
> +	.read		= bL_status_read,
> +};
> +
> +static struct miscdevice bL_status_device = {
> +	MISC_DYNAMIC_MINOR,
> +	"bL_status",
> +	&bL_status_fops
> +};
> +
>   /*
>    * Enable cluster-level coherency, in preparation for turning on the MMU.
>    */
> @@ -319,3 +366,20 @@ static int __init exynos_mcpm_init(void)
>   }
>
>   early_initcall(exynos_mcpm_init);
> +
> +static int __init exynos_bl_status_init(void)
> +{
> +	int ret;
> +
> +	if (!soc_is_exynos5420())
> +		return -ENODEV;
> +
> +	ret = misc_register(&bL_status_device);
> +	if (ret) {
> +		pr_info("bl_status not available\n");
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +late_initcall(exynos_bl_status_init);
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

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

* [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
@ 2014-04-28 11:25         ` Daniel Lezcano
  0 siblings, 0 replies; 60+ messages in thread
From: Daniel Lezcano @ 2014-04-28 11:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
> Add a user interface to check the core and cluster status on
> Exynos5420. This can be utilized while debugging mcpm issues.
> cat /dev/bL_status will show the current power status of all
> the 8 cores along with the cluster.
>
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> ---

Hi Abhilash,

I don't think you should add this file.

1. big Little is not exynos specific
2. /dev is not for the purpose of your patch

So I would recommend:

1. create a generic infra-structure for all the big.Little
2. and/or use debugfs

Furthermore, how is it usable ? Will you read the file every 2ms to 
check the cluster status, knowing it will be woken up by the read 
operation ?

Frankly speaking, it would make sense to add traces in mcpm.c (if they 
aren't already there - did not check).

>   arch/arm/mach-exynos/mcpm-exynos.c | 64 ++++++++++++++++++++++++++++++++++++++
>   1 file changed, 64 insertions(+)
>
> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
> index f9977bf..83428b0 100644
> --- a/arch/arm/mach-exynos/mcpm-exynos.c
> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
> @@ -269,6 +269,53 @@ static void __init exynos_mcpm_usage_count_init(void)
>   	cpu_use_count[cpu][cluster] = 1;
>   }
>
> +static size_t bL_check_status(char *info)
> +{
> +	size_t len = 0;
> +	int i;
> +
> +	len += sprintf(&info[len], "\t0 1 2 3 L2\n");
> +	len += sprintf(&info[len], "[A15]   ");
> +	for (i = 0; i < 4; i++) {
> +		len += sprintf(&info[len], "%d ",
> +			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
> +	}
> +	len += sprintf(&info[len], "%d\n",
> +			(readl(EXYNOS_COMMON_STATUS(0)) & 0x3) == 3 ? 1 : 0);
> +
> +	len += sprintf(&info[len], "[A7]    ");
> +	for (i = 4; i < 8; i++)
> +		len += sprintf(&info[len], "%d ",
> +			(readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1 : 0);
> +	len += sprintf(&info[len], "%d\n\n",
> +			(readl(EXYNOS_COMMON_STATUS(1)) & 0x3) == 3 ? 1 : 0);
> +
> +	return len;
> +}
> +
> +static ssize_t bL_status_read(struct file *file, char __user *buf,
> +			size_t len, loff_t *pos)
> +{
> +	size_t count = 0;
> +	char info[100];
> +
> +	count = bL_check_status(info);
> +	if (count < 0)
> +		return -EINVAL;
> +
> +	return simple_read_from_buffer(buf, len, pos, info, count);
> +}
> +
> +static const struct file_operations bL_status_fops = {
> +	.read		= bL_status_read,
> +};
> +
> +static struct miscdevice bL_status_device = {
> +	MISC_DYNAMIC_MINOR,
> +	"bL_status",
> +	&bL_status_fops
> +};
> +
>   /*
>    * Enable cluster-level coherency, in preparation for turning on the MMU.
>    */
> @@ -319,3 +366,20 @@ static int __init exynos_mcpm_init(void)
>   }
>
>   early_initcall(exynos_mcpm_init);
> +
> +static int __init exynos_bl_status_init(void)
> +{
> +	int ret;
> +
> +	if (!soc_is_exynos5420())
> +		return -ENODEV;
> +
> +	ret = misc_register(&bL_status_device);
> +	if (ret) {
> +		pr_info("bl_status not available\n");
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +late_initcall(exynos_bl_status_init);
>


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

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

* Re: [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
  2014-04-28 11:25         ` Daniel Lezcano
@ 2014-04-28 12:49             ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-28 12:49 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Nicolas Pitre, Dave Martin, Lorenzo Pieralisi, linux-arm-kernel,
	Kukjin Kim, Tomasz Figa, Andrew Bresticker, Thomas P Abraham,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland, devicetree,
	Grant Likely, robh+dt, Will Deacon, Arnd Bergmann

On Mon, Apr 28, 2014 at 4:55 PM, Daniel Lezcano
<daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
>>
>> Add a user interface to check the core and cluster status on
>> Exynos5420. This can be utilized while debugging mcpm issues.
>> cat /dev/bL_status will show the current power status of all
>> the 8 cores along with the cluster.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>
>
> Hi Abhilash,

Hi Daniel,
>
> I don't think you should add this file.
>
> 1. big Little is not exynos specific
But the core control/status bits that I am accessing are exynos
specific and currently it is being enabled only on 5420.
> 2. /dev is not for the purpose of your patch
OK.
>
> So I would recommend:
>
> 1. create a generic infra-structure for all the big.Little
> 2. and/or use debugfs
>
> Furthermore, how is it usable ? Will you read the file every 2ms to check
> the cluster status, knowing it will be woken up by the read operation ?
This was just a quick way to check the power status of the
cores/cluster during cpufreq controlled core switching. Maybe not as
useful in case of cpuidle.
>
> Frankly speaking, it would make sense to add traces in mcpm.c (if they
> aren't already there - did not check).
Fair enough, the core bL_switcher code does have code for trace
events. I can check more on that.

Regards,
Abhilash
>
>
>>   arch/arm/mach-exynos/mcpm-exynos.c | 64
>> ++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 64 insertions(+)
>>
>> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c
>> b/arch/arm/mach-exynos/mcpm-exynos.c
>> index f9977bf..83428b0 100644
>> --- a/arch/arm/mach-exynos/mcpm-exynos.c
>> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
>> @@ -269,6 +269,53 @@ static void __init exynos_mcpm_usage_count_init(void)
>>         cpu_use_count[cpu][cluster] = 1;
>>   }
>>
>> +static size_t bL_check_status(char *info)
>> +{
>> +       size_t len = 0;
>> +       int i;
>> +
>> +       len += sprintf(&info[len], "\t0 1 2 3 L2\n");
>> +       len += sprintf(&info[len], "[A15]   ");
>> +       for (i = 0; i < 4; i++) {
>> +               len += sprintf(&info[len], "%d ",
>> +                       (readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1
>> : 0);
>> +       }
>> +       len += sprintf(&info[len], "%d\n",
>> +                       (readl(EXYNOS_COMMON_STATUS(0)) & 0x3) == 3 ? 1 :
>> 0);
>> +
>> +       len += sprintf(&info[len], "[A7]    ");
>> +       for (i = 4; i < 8; i++)
>> +               len += sprintf(&info[len], "%d ",
>> +                       (readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1
>> : 0);
>> +       len += sprintf(&info[len], "%d\n\n",
>> +                       (readl(EXYNOS_COMMON_STATUS(1)) & 0x3) == 3 ? 1 :
>> 0);
>> +
>> +       return len;
>> +}
>> +
>> +static ssize_t bL_status_read(struct file *file, char __user *buf,
>> +                       size_t len, loff_t *pos)
>> +{
>> +       size_t count = 0;
>> +       char info[100];
>> +
>> +       count = bL_check_status(info);
>> +       if (count < 0)
>> +               return -EINVAL;
>> +
>> +       return simple_read_from_buffer(buf, len, pos, info, count);
>> +}
>> +
>> +static const struct file_operations bL_status_fops = {
>> +       .read           = bL_status_read,
>> +};
>> +
>> +static struct miscdevice bL_status_device = {
>> +       MISC_DYNAMIC_MINOR,
>> +       "bL_status",
>> +       &bL_status_fops
>> +};
>> +
>>   /*
>>    * Enable cluster-level coherency, in preparation for turning on the
>> MMU.
>>    */
>> @@ -319,3 +366,20 @@ static int __init exynos_mcpm_init(void)
>>   }
>>
>>   early_initcall(exynos_mcpm_init);
>> +
>> +static int __init exynos_bl_status_init(void)
>> +{
>> +       int ret;
>> +
>> +       if (!soc_is_exynos5420())
>> +               return -ENODEV;
>> +
>> +       ret = misc_register(&bL_status_device);
>> +       if (ret) {
>> +               pr_info("bl_status not available\n");
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +late_initcall(exynos_bl_status_init);
>>
>
>
> --
>  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
@ 2014-04-28 12:49             ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-28 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 28, 2014 at 4:55 PM, Daniel Lezcano
<daniel.lezcano@linaro.org> wrote:
> On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
>>
>> Add a user interface to check the core and cluster status on
>> Exynos5420. This can be utilized while debugging mcpm issues.
>> cat /dev/bL_status will show the current power status of all
>> the 8 cores along with the cluster.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> ---
>
>
> Hi Abhilash,

Hi Daniel,
>
> I don't think you should add this file.
>
> 1. big Little is not exynos specific
But the core control/status bits that I am accessing are exynos
specific and currently it is being enabled only on 5420.
> 2. /dev is not for the purpose of your patch
OK.
>
> So I would recommend:
>
> 1. create a generic infra-structure for all the big.Little
> 2. and/or use debugfs
>
> Furthermore, how is it usable ? Will you read the file every 2ms to check
> the cluster status, knowing it will be woken up by the read operation ?
This was just a quick way to check the power status of the
cores/cluster during cpufreq controlled core switching. Maybe not as
useful in case of cpuidle.
>
> Frankly speaking, it would make sense to add traces in mcpm.c (if they
> aren't already there - did not check).
Fair enough, the core bL_switcher code does have code for trace
events. I can check more on that.

Regards,
Abhilash
>
>
>>   arch/arm/mach-exynos/mcpm-exynos.c | 64
>> ++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 64 insertions(+)
>>
>> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c
>> b/arch/arm/mach-exynos/mcpm-exynos.c
>> index f9977bf..83428b0 100644
>> --- a/arch/arm/mach-exynos/mcpm-exynos.c
>> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
>> @@ -269,6 +269,53 @@ static void __init exynos_mcpm_usage_count_init(void)
>>         cpu_use_count[cpu][cluster] = 1;
>>   }
>>
>> +static size_t bL_check_status(char *info)
>> +{
>> +       size_t len = 0;
>> +       int i;
>> +
>> +       len += sprintf(&info[len], "\t0 1 2 3 L2\n");
>> +       len += sprintf(&info[len], "[A15]   ");
>> +       for (i = 0; i < 4; i++) {
>> +               len += sprintf(&info[len], "%d ",
>> +                       (readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1
>> : 0);
>> +       }
>> +       len += sprintf(&info[len], "%d\n",
>> +                       (readl(EXYNOS_COMMON_STATUS(0)) & 0x3) == 3 ? 1 :
>> 0);
>> +
>> +       len += sprintf(&info[len], "[A7]    ");
>> +       for (i = 4; i < 8; i++)
>> +               len += sprintf(&info[len], "%d ",
>> +                       (readl(EXYNOS_ARM_CORE_STATUS(i)) & 0x3) == 3 ? 1
>> : 0);
>> +       len += sprintf(&info[len], "%d\n\n",
>> +                       (readl(EXYNOS_COMMON_STATUS(1)) & 0x3) == 3 ? 1 :
>> 0);
>> +
>> +       return len;
>> +}
>> +
>> +static ssize_t bL_status_read(struct file *file, char __user *buf,
>> +                       size_t len, loff_t *pos)
>> +{
>> +       size_t count = 0;
>> +       char info[100];
>> +
>> +       count = bL_check_status(info);
>> +       if (count < 0)
>> +               return -EINVAL;
>> +
>> +       return simple_read_from_buffer(buf, len, pos, info, count);
>> +}
>> +
>> +static const struct file_operations bL_status_fops = {
>> +       .read           = bL_status_read,
>> +};
>> +
>> +static struct miscdevice bL_status_device = {
>> +       MISC_DYNAMIC_MINOR,
>> +       "bL_status",
>> +       &bL_status_fops
>> +};
>> +
>>   /*
>>    * Enable cluster-level coherency, in preparation for turning on the
>> MMU.
>>    */
>> @@ -319,3 +366,20 @@ static int __init exynos_mcpm_init(void)
>>   }
>>
>>   early_initcall(exynos_mcpm_init);
>> +
>> +static int __init exynos_bl_status_init(void)
>> +{
>> +       int ret;
>> +
>> +       if (!soc_is_exynos5420())
>> +               return -ENODEV;
>> +
>> +       ret = misc_register(&bL_status_device);
>> +       if (ret) {
>> +               pr_info("bl_status not available\n");
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +late_initcall(exynos_bl_status_init);
>>
>
>
> --
>  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs
>
> Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-04-28 17:44       ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 60+ messages in thread
From: Lorenzo Pieralisi @ 2014-04-28 17:44 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: nicolas.pitre, Mark Rutland, kesavan.abhilash, kgene.kim, arnd,
	devicetree, abrestic, t.figa, daniel.lezcano, Will Deacon,
	robh+dt, thomas.ab, grant.likely, Dave P Martin,
	linux-arm-kernel, inderpal.s

On Sat, Apr 26, 2014 at 05:05:47PM +0100, Abhilash Kesavan wrote:
> Add machine-dependent MCPM call-backs for Exynos5420. These are used
> to power up/down the secondary CPUs during boot, shutdown, s2r and
> switching.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> ---
>  arch/arm/mach-exynos/Kconfig       |   8 +
>  arch/arm/mach-exynos/Makefile      |   2 +
>  arch/arm/mach-exynos/mcpm-exynos.c | 321 +++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-exynos/regs-pmu.h    |   3 +
>  4 files changed, 334 insertions(+)
>  create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c
> 
> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
> index fc8bf18..1602abc 100644
> --- a/arch/arm/mach-exynos/Kconfig
> +++ b/arch/arm/mach-exynos/Kconfig
> @@ -110,4 +110,12 @@ config SOC_EXYNOS5440
> 
>  endmenu
> 
> +config EXYNOS5420_MCPM
> +       bool "Exynos5420 Multi-Cluster PM support"
> +       depends on MCPM && SOC_EXYNOS5420
> +       select ARM_CCI
> +       help
> +         This is needed to provide CPU and cluster power management
> +         on Exynos5420 implementing big.LITTLE.
> +
>  endif
> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
> index a656dbe..01bc9b9 100644
> --- a/arch/arm/mach-exynos/Makefile
> +++ b/arch/arm/mach-exynos/Makefile
> @@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)     += firmware.o
> 
>  plus_sec := $(call as-instr,.arch_extension sec,+sec)
>  AFLAGS_exynos-smc.o            :=-Wa,-march=armv7-a$(plus_sec)
> +
> +obj-$(CONFIG_EXYNOS5420_MCPM)  += mcpm-exynos.o
> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
> new file mode 100644
> index 0000000..f9977bf
> --- /dev/null
> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
> @@ -0,0 +1,321 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *             http://www.samsung.com
> + *
> + * arch/arm/mach-exynos/mcpm-exynos.c
> + *
> + * Based on arch/arm/mach-vexpress/dcscb.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/uaccess.h>
> +#include <linux/miscdevice.h>
> +#include <linux/fs.h>
> +#include <linux/delay.h>
> +#include <linux/arm-cci.h>

Alphabetical order please.

> +
> +#include <asm/mcpm.h>
> +#include <asm/cputype.h>
> +#include <asm/cp15.h>
> +
> +#include <plat/cpu.h>
> +
> +#include "regs-pmu.h"
> +#include "common.h"
> +
> +#define EXYNOS5420_CPUS_PER_CLUSTER    4
> +#define EXYNOS5420_NR_CLUSTERS         2
> +
> +/* Secondary CPU entry point */
> +#define REG_ENTRY_ADDR         (S5P_VA_SYSRAM_NS + 0x1C)
> +
> +/*
> + * The common v7_exit_coherency_flush API could not be used because of the
> + * Erratum 799270 workaround. This macro is the same as the common one (in
> + * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
> + */
> +#define exynos_v7_exit_coherency_flush(level) \
> +       asm volatile( \
> +       "stmfd  sp!, {fp, ip}\n\t"\
> +       "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
> +       "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
> +       "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
> +       "isb\n\t"\
> +       "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
> +       "clrex\n\t"\
> +       "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
> +       "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
> +       /* Dummy Load of a device register to avoid Erratum 799270 */ \
> +       "ldr    r4, [%0]\n\t" \
> +       "and    r4, r4, #0\n\t" \
> +       "orr    r0, r0, r4\n\t" \
> +       "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
> +       "isb\n\t" \
> +       "dsb\n\t" \
> +       "ldmfd  sp!, {fp, ip}" \
> +       : \
> +       : "Ir" (S5P_INFORM0) \
> +       : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
> +         "r9", "r10", "lr", "memory")
> +

Still investigating to see if can work around errata 799270 in a
different fashion, will keep you posted.

> +/*
> + * We can't use regular spinlocks. In the switcher case, it is possible
> + * for an outbound CPU to call power_down() after its inbound counterpart
> + * is already live using the same logical CPU number which trips lockdep
> + * debugging.
> + */
> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +static int
> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
> +
> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
> +{
> +       unsigned int tries = 100;
> +       unsigned int val = 0;
> +
> +       if (enable) {
> +               exynos_cluster_powerup(cluster);
> +               val = S5P_CORE_LOCAL_PWR_EN;
> +       } else {
> +               exynos_cluster_powerdown(cluster);
> +       }
> +
> +       /* Wait until cluster power control is applied */
> +       while (tries--) {
> +               if (exynos_cluster_power_state(cluster) == val)

Do you really need val ?

> +                       return 0;
> +
> +               cpu_relax();
> +       }
> +       pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
> +               enable ? "on" : "off");
> +
> +       return -ETIMEDOUT;
> +}
> +
> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
> +{
> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +       unsigned int err;
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +               cluster >= EXYNOS5420_NR_CLUSTERS)
> +               return -EINVAL;
> +
> +       /*
> +        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
> +        * variant exists, we need to disable IRQs manually here.
> +        */
> +       local_irq_disable();
> +       arch_spin_lock(&exynos_mcpm_lock);
> +
> +       cpu_use_count[cpu][cluster]++;
> +       if (cpu_use_count[cpu][cluster] == 1) {
> +               bool was_cluster_down =
> +                       __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
> +
> +               /*
> +                * Turn on the cluster (L2/COMMON) and then power on the cores.
> +                * TODO: Turn off the clusters when all cores in the cluster
> +                * are down to achieve significant power savings.
> +                */
> +               if (was_cluster_down) {
> +                       err = exynos_cluster_power_control(cluster, 1);
> +                       if (err) {
> +                               exynos_cluster_power_control(cluster, 0);
> +                               return err;

You must not return without undoing what you should (irqs and locking).

> +                       }
> +               }
> +
> +               exynos_cpu_powerup(cpunr);
> +
> +               /* CPU should be powered up there */
> +               /* Also setup Cluster Power Sequence here */

Stale comment ?

> +       } else if (cpu_use_count[cpu][cluster] != 2) {
> +               /*
> +                * The only possible values are:
> +                * 0 = CPU down
> +                * 1 = CPU (still) up
> +                * 2 = CPU requested to be up before it had a chance
> +                *     to actually make itself down.
> +                * Any other value is a bug.
> +                */
> +               BUG();
> +       }
> +
> +       arch_spin_unlock(&exynos_mcpm_lock);
> +       local_irq_enable();
> +
> +       return 0;
> +}
> +
> +static void exynos_power_down(void)
> +{
> +       unsigned int mpidr, cpu, cluster;
> +       bool last_man = false, skip_wfi = false;
> +       unsigned int cpunr;
> +
> +       mpidr = read_cpuid_mpidr();
> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +       cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       __mcpm_cpu_going_down(cpu, cluster);
> +
> +       arch_spin_lock(&exynos_mcpm_lock);
> +       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +       cpu_use_count[cpu][cluster]--;
> +       if (cpu_use_count[cpu][cluster] == 0) {
> +               int cnt = 0, i;
> +
> +               exynos_cpu_powerdown(cpunr);
> +               for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
> +                       cnt += cpu_use_count[i][cluster];
> +               if (cnt == 0)
> +                       last_man = true;

		for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
			if (cpu_use_count[i][cluster])
				break;
		last_man = i == EXYNOS5420_CPUS_PER_CLUSTER;

and get rid of cnt.

> +       } else if (cpu_use_count[cpu][cluster] == 1) {
> +               /*
> +                * A power_up request went ahead of us.
> +                * Even if we do not want to shut this CPU down,
> +                * the caller expects a certain state as if the WFI
> +                * was aborted.  So let's continue with cache cleaning.
> +                */
> +               skip_wfi = true;
> +       } else {
> +               BUG();
> +       }
> +
> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +
> +               /* Flush all cache levels for this cluster. */
> +               exynos_v7_exit_coherency_flush(all);
> +
> +               /*
> +                * Disable cluster-level coherency by masking
> +                * incoming snoops and DVM messages:
> +                */
> +               cci_disable_port_by_cpu(mpidr);
> +
> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> +       } else {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +
> +               /* Disable and flush the local CPU cache. */
> +               exynos_v7_exit_coherency_flush(louis);
> +       }
> +
> +       __mcpm_cpu_down(cpu, cluster);
> +
> +       /* Now we are prepared for power-down, do it: */
> +       if (!skip_wfi)
> +               wfi();
> +
> +       /* Not dead at this point?  Let our caller cope. */
> +}
> +
> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
> +{
> +       unsigned int tries = 100;
> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       /* Wait for the core state to be OFF */
> +       while (tries--) {
> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
> +                       if ((exynos_cpu_power_state(cpunr) == 0))
> +                               return 0; /* success: the CPU is halted */
> +               }
> +
> +               /* Otherwise, wait and retry: */
> +               msleep(1);
> +       }
> +
> +       return -ETIMEDOUT; /* timeout */
> +}
> +
> +static const struct mcpm_platform_ops exynos_power_ops = {
> +       .power_up               = exynos_power_up,
> +       .power_down             = exynos_power_down,
> +       .power_down_finish      = exynos_power_down_finish,
> +};
> +
> +static void __init exynos_mcpm_usage_count_init(void)
> +{
> +       unsigned int mpidr, cpu, cluster;
> +
> +       mpidr = read_cpuid_mpidr();
> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       cpu_use_count[cpu][cluster] = 1;
> +}
> +
> +/*
> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> + */
> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> +{
> +       asm volatile ("\n"
> +       "cmp    r0, #1\n"
> +       "bxne   lr\n"
> +       "b      cci_enable_port_for_self");
> +}

How many times are we going to duplicate this function before we decide
to move it to a common header ?

> +static int __init exynos_mcpm_init(void)
> +{
> +       int ret = 0;
> +
> +       if (!soc_is_exynos5420())
> +               return -ENODEV;

I do not particularly like these soc_is* stubs, but it is just a matter
of taste.

Thanks,
Lorenzo

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-28 17:44       ` Lorenzo Pieralisi
  0 siblings, 0 replies; 60+ messages in thread
From: Lorenzo Pieralisi @ 2014-04-28 17:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 26, 2014 at 05:05:47PM +0100, Abhilash Kesavan wrote:
> Add machine-dependent MCPM call-backs for Exynos5420. These are used
> to power up/down the secondary CPUs during boot, shutdown, s2r and
> switching.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> ---
>  arch/arm/mach-exynos/Kconfig       |   8 +
>  arch/arm/mach-exynos/Makefile      |   2 +
>  arch/arm/mach-exynos/mcpm-exynos.c | 321 +++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-exynos/regs-pmu.h    |   3 +
>  4 files changed, 334 insertions(+)
>  create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c
> 
> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
> index fc8bf18..1602abc 100644
> --- a/arch/arm/mach-exynos/Kconfig
> +++ b/arch/arm/mach-exynos/Kconfig
> @@ -110,4 +110,12 @@ config SOC_EXYNOS5440
> 
>  endmenu
> 
> +config EXYNOS5420_MCPM
> +       bool "Exynos5420 Multi-Cluster PM support"
> +       depends on MCPM && SOC_EXYNOS5420
> +       select ARM_CCI
> +       help
> +         This is needed to provide CPU and cluster power management
> +         on Exynos5420 implementing big.LITTLE.
> +
>  endif
> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
> index a656dbe..01bc9b9 100644
> --- a/arch/arm/mach-exynos/Makefile
> +++ b/arch/arm/mach-exynos/Makefile
> @@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)     += firmware.o
> 
>  plus_sec := $(call as-instr,.arch_extension sec,+sec)
>  AFLAGS_exynos-smc.o            :=-Wa,-march=armv7-a$(plus_sec)
> +
> +obj-$(CONFIG_EXYNOS5420_MCPM)  += mcpm-exynos.o
> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
> new file mode 100644
> index 0000000..f9977bf
> --- /dev/null
> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
> @@ -0,0 +1,321 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *             http://www.samsung.com
> + *
> + * arch/arm/mach-exynos/mcpm-exynos.c
> + *
> + * Based on arch/arm/mach-vexpress/dcscb.c
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/uaccess.h>
> +#include <linux/miscdevice.h>
> +#include <linux/fs.h>
> +#include <linux/delay.h>
> +#include <linux/arm-cci.h>

Alphabetical order please.

> +
> +#include <asm/mcpm.h>
> +#include <asm/cputype.h>
> +#include <asm/cp15.h>
> +
> +#include <plat/cpu.h>
> +
> +#include "regs-pmu.h"
> +#include "common.h"
> +
> +#define EXYNOS5420_CPUS_PER_CLUSTER    4
> +#define EXYNOS5420_NR_CLUSTERS         2
> +
> +/* Secondary CPU entry point */
> +#define REG_ENTRY_ADDR         (S5P_VA_SYSRAM_NS + 0x1C)
> +
> +/*
> + * The common v7_exit_coherency_flush API could not be used because of the
> + * Erratum 799270 workaround. This macro is the same as the common one (in
> + * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
> + */
> +#define exynos_v7_exit_coherency_flush(level) \
> +       asm volatile( \
> +       "stmfd  sp!, {fp, ip}\n\t"\
> +       "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
> +       "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
> +       "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
> +       "isb\n\t"\
> +       "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
> +       "clrex\n\t"\
> +       "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
> +       "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
> +       /* Dummy Load of a device register to avoid Erratum 799270 */ \
> +       "ldr    r4, [%0]\n\t" \
> +       "and    r4, r4, #0\n\t" \
> +       "orr    r0, r0, r4\n\t" \
> +       "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
> +       "isb\n\t" \
> +       "dsb\n\t" \
> +       "ldmfd  sp!, {fp, ip}" \
> +       : \
> +       : "Ir" (S5P_INFORM0) \
> +       : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
> +         "r9", "r10", "lr", "memory")
> +

Still investigating to see if can work around errata 799270 in a
different fashion, will keep you posted.

> +/*
> + * We can't use regular spinlocks. In the switcher case, it is possible
> + * for an outbound CPU to call power_down() after its inbound counterpart
> + * is already live using the same logical CPU number which trips lockdep
> + * debugging.
> + */
> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +static int
> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
> +
> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
> +{
> +       unsigned int tries = 100;
> +       unsigned int val = 0;
> +
> +       if (enable) {
> +               exynos_cluster_powerup(cluster);
> +               val = S5P_CORE_LOCAL_PWR_EN;
> +       } else {
> +               exynos_cluster_powerdown(cluster);
> +       }
> +
> +       /* Wait until cluster power control is applied */
> +       while (tries--) {
> +               if (exynos_cluster_power_state(cluster) == val)

Do you really need val ?

> +                       return 0;
> +
> +               cpu_relax();
> +       }
> +       pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
> +               enable ? "on" : "off");
> +
> +       return -ETIMEDOUT;
> +}
> +
> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
> +{
> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +       unsigned int err;
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +               cluster >= EXYNOS5420_NR_CLUSTERS)
> +               return -EINVAL;
> +
> +       /*
> +        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
> +        * variant exists, we need to disable IRQs manually here.
> +        */
> +       local_irq_disable();
> +       arch_spin_lock(&exynos_mcpm_lock);
> +
> +       cpu_use_count[cpu][cluster]++;
> +       if (cpu_use_count[cpu][cluster] == 1) {
> +               bool was_cluster_down =
> +                       __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
> +
> +               /*
> +                * Turn on the cluster (L2/COMMON) and then power on the cores.
> +                * TODO: Turn off the clusters when all cores in the cluster
> +                * are down to achieve significant power savings.
> +                */
> +               if (was_cluster_down) {
> +                       err = exynos_cluster_power_control(cluster, 1);
> +                       if (err) {
> +                               exynos_cluster_power_control(cluster, 0);
> +                               return err;

You must not return without undoing what you should (irqs and locking).

> +                       }
> +               }
> +
> +               exynos_cpu_powerup(cpunr);
> +
> +               /* CPU should be powered up there */
> +               /* Also setup Cluster Power Sequence here */

Stale comment ?

> +       } else if (cpu_use_count[cpu][cluster] != 2) {
> +               /*
> +                * The only possible values are:
> +                * 0 = CPU down
> +                * 1 = CPU (still) up
> +                * 2 = CPU requested to be up before it had a chance
> +                *     to actually make itself down.
> +                * Any other value is a bug.
> +                */
> +               BUG();
> +       }
> +
> +       arch_spin_unlock(&exynos_mcpm_lock);
> +       local_irq_enable();
> +
> +       return 0;
> +}
> +
> +static void exynos_power_down(void)
> +{
> +       unsigned int mpidr, cpu, cluster;
> +       bool last_man = false, skip_wfi = false;
> +       unsigned int cpunr;
> +
> +       mpidr = read_cpuid_mpidr();
> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +       cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       __mcpm_cpu_going_down(cpu, cluster);
> +
> +       arch_spin_lock(&exynos_mcpm_lock);
> +       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +       cpu_use_count[cpu][cluster]--;
> +       if (cpu_use_count[cpu][cluster] == 0) {
> +               int cnt = 0, i;
> +
> +               exynos_cpu_powerdown(cpunr);
> +               for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
> +                       cnt += cpu_use_count[i][cluster];
> +               if (cnt == 0)
> +                       last_man = true;

		for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
			if (cpu_use_count[i][cluster])
				break;
		last_man = i == EXYNOS5420_CPUS_PER_CLUSTER;

and get rid of cnt.

> +       } else if (cpu_use_count[cpu][cluster] == 1) {
> +               /*
> +                * A power_up request went ahead of us.
> +                * Even if we do not want to shut this CPU down,
> +                * the caller expects a certain state as if the WFI
> +                * was aborted.  So let's continue with cache cleaning.
> +                */
> +               skip_wfi = true;
> +       } else {
> +               BUG();
> +       }
> +
> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +
> +               /* Flush all cache levels for this cluster. */
> +               exynos_v7_exit_coherency_flush(all);
> +
> +               /*
> +                * Disable cluster-level coherency by masking
> +                * incoming snoops and DVM messages:
> +                */
> +               cci_disable_port_by_cpu(mpidr);
> +
> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> +       } else {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +
> +               /* Disable and flush the local CPU cache. */
> +               exynos_v7_exit_coherency_flush(louis);
> +       }
> +
> +       __mcpm_cpu_down(cpu, cluster);
> +
> +       /* Now we are prepared for power-down, do it: */
> +       if (!skip_wfi)
> +               wfi();
> +
> +       /* Not dead at this point?  Let our caller cope. */
> +}
> +
> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
> +{
> +       unsigned int tries = 100;
> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       /* Wait for the core state to be OFF */
> +       while (tries--) {
> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
> +                       if ((exynos_cpu_power_state(cpunr) == 0))
> +                               return 0; /* success: the CPU is halted */
> +               }
> +
> +               /* Otherwise, wait and retry: */
> +               msleep(1);
> +       }
> +
> +       return -ETIMEDOUT; /* timeout */
> +}
> +
> +static const struct mcpm_platform_ops exynos_power_ops = {
> +       .power_up               = exynos_power_up,
> +       .power_down             = exynos_power_down,
> +       .power_down_finish      = exynos_power_down_finish,
> +};
> +
> +static void __init exynos_mcpm_usage_count_init(void)
> +{
> +       unsigned int mpidr, cpu, cluster;
> +
> +       mpidr = read_cpuid_mpidr();
> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       cpu_use_count[cpu][cluster] = 1;
> +}
> +
> +/*
> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> + */
> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> +{
> +       asm volatile ("\n"
> +       "cmp    r0, #1\n"
> +       "bxne   lr\n"
> +       "b      cci_enable_port_for_self");
> +}

How many times are we going to duplicate this function before we decide
to move it to a common header ?

> +static int __init exynos_mcpm_init(void)
> +{
> +       int ret = 0;
> +
> +       if (!soc_is_exynos5420())
> +               return -ENODEV;

I do not particularly like these soc_is* stubs, but it is just a matter
of taste.

Thanks,
Lorenzo

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-28 17:44       ` Lorenzo Pieralisi
@ 2014-04-29  3:32           ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-29  3:32 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave P Martin,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, arnd-r2nGTMty4D4

Hi Lorenzo,

Thanks for the review.

[...]

>> +#include <linux/kernel.h>
>> +#include <linux/io.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/fs.h>
>> +#include <linux/delay.h>
>> +#include <linux/arm-cci.h>
>
> Alphabetical order please.
Will fix.

[...]
>> +#define exynos_v7_exit_coherency_flush(level) \
>> +       asm volatile( \
>> +       "stmfd  sp!, {fp, ip}\n\t"\
>> +       "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
>> +       "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
>> +       "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
>> +       "isb\n\t"\
>> +       "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
>> +       "clrex\n\t"\
>> +       "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
>> +       "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
>> +       /* Dummy Load of a device register to avoid Erratum 799270 */ \
>> +       "ldr    r4, [%0]\n\t" \
>> +       "and    r4, r4, #0\n\t" \
>> +       "orr    r0, r0, r4\n\t" \
>> +       "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
>> +       "isb\n\t" \
>> +       "dsb\n\t" \
>> +       "ldmfd  sp!, {fp, ip}" \
>> +       : \
>> +       : "Ir" (S5P_INFORM0) \
>> +       : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
>> +         "r9", "r10", "lr", "memory")
>> +
>
> Still investigating to see if can work around errata 799270 in a
> different fashion, will keep you posted.
Thanks.
>
>> +/*
>> + * We can't use regular spinlocks. In the switcher case, it is possible
>> + * for an outbound CPU to call power_down() after its inbound counterpart
>> + * is already live using the same logical CPU number which trips lockdep
>> + * debugging.
>> + */
>> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
>> +static int
>> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
>> +
>> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
>> +{
>> +       unsigned int tries = 100;
>> +       unsigned int val = 0;
>> +
>> +       if (enable) {
>> +               exynos_cluster_powerup(cluster);
>> +               val = S5P_CORE_LOCAL_PWR_EN;
>> +       } else {
>> +               exynos_cluster_powerdown(cluster);
>> +       }
>> +
>> +       /* Wait until cluster power control is applied */
>> +       while (tries--) {
>> +               if (exynos_cluster_power_state(cluster) == val)
>
> Do you really need val ?
Yes, val can be 0x0 or 0x3 depending on whether we want to enable or
disable the cluster.
>
>> +                       return 0;
>> +
>> +               cpu_relax();
>> +       }
>> +       pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
>> +               enable ? "on" : "off");
>> +
>> +       return -ETIMEDOUT;
>> +}
>> +
>> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
>> +{
>> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +       unsigned int err;
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +               cluster >= EXYNOS5420_NR_CLUSTERS)
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
>> +        * variant exists, we need to disable IRQs manually here.
>> +        */
>> +       local_irq_disable();
>> +       arch_spin_lock(&exynos_mcpm_lock);
>> +
>> +       cpu_use_count[cpu][cluster]++;
>> +       if (cpu_use_count[cpu][cluster] == 1) {
>> +               bool was_cluster_down =
>> +                       __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
>> +
>> +               /*
>> +                * Turn on the cluster (L2/COMMON) and then power on the cores.
>> +                * TODO: Turn off the clusters when all cores in the cluster
>> +                * are down to achieve significant power savings.
>> +                */
>> +               if (was_cluster_down) {
>> +                       err = exynos_cluster_power_control(cluster, 1);
>> +                       if (err) {
>> +                               exynos_cluster_power_control(cluster, 0);
>> +                               return err;
>
> You must not return without undoing what you should (irqs and locking).
Will do so.
>
>> +                       }
>> +               }
>> +
>> +               exynos_cpu_powerup(cpunr);
>> +
>> +               /* CPU should be powered up there */
>> +               /* Also setup Cluster Power Sequence here */
>
> Stale comment ?
Will remove.
>
>> +       } else if (cpu_use_count[cpu][cluster] != 2) {
>> +               /*
>> +                * The only possible values are:
>> +                * 0 = CPU down
>> +                * 1 = CPU (still) up
>> +                * 2 = CPU requested to be up before it had a chance
>> +                *     to actually make itself down.
>> +                * Any other value is a bug.
>> +                */
>> +               BUG();
>> +       }
>> +
>> +       arch_spin_unlock(&exynos_mcpm_lock);
>> +       local_irq_enable();
>> +
>> +       return 0;
>> +}
>> +
>> +static void exynos_power_down(void)
>> +{
>> +       unsigned int mpidr, cpu, cluster;
>> +       bool last_man = false, skip_wfi = false;
>> +       unsigned int cpunr;
>> +
>> +       mpidr = read_cpuid_mpidr();
>> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +       cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       __mcpm_cpu_going_down(cpu, cluster);
>> +
>> +       arch_spin_lock(&exynos_mcpm_lock);
>> +       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
>> +       cpu_use_count[cpu][cluster]--;
>> +       if (cpu_use_count[cpu][cluster] == 0) {
>> +               int cnt = 0, i;
>> +
>> +               exynos_cpu_powerdown(cpunr);
>> +               for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
>> +                       cnt += cpu_use_count[i][cluster];
>> +               if (cnt == 0)
>> +                       last_man = true;
>
>                 for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
>                         if (cpu_use_count[i][cluster])
>                                 break;
>                 last_man = i == EXYNOS5420_CPUS_PER_CLUSTER;
>
> and get rid of cnt.
OK.
>
>> +       } else if (cpu_use_count[cpu][cluster] == 1) {
>> +               /*
>> +                * A power_up request went ahead of us.
>> +                * Even if we do not want to shut this CPU down,
>> +                * the caller expects a certain state as if the WFI
>> +                * was aborted.  So let's continue with cache cleaning.
>> +                */
>> +               skip_wfi = true;
>> +       } else {
>> +               BUG();
>> +       }
>> +
>> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +               /* Flush all cache levels for this cluster. */
>> +               exynos_v7_exit_coherency_flush(all);
>> +
>> +               /*
>> +                * Disable cluster-level coherency by masking
>> +                * incoming snoops and DVM messages:
>> +                */
>> +               cci_disable_port_by_cpu(mpidr);
>> +
>> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
>> +       } else {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +               /* Disable and flush the local CPU cache. */
>> +               exynos_v7_exit_coherency_flush(louis);
>> +       }
>> +
>> +       __mcpm_cpu_down(cpu, cluster);
>> +
>> +       /* Now we are prepared for power-down, do it: */
>> +       if (!skip_wfi)
>> +               wfi();
>> +
>> +       /* Not dead at this point?  Let our caller cope. */
>> +}
>> +
>> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
>> +{
>> +       unsigned int tries = 100;
>> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       /* Wait for the core state to be OFF */
>> +       while (tries--) {
>> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
>> +                       if ((exynos_cpu_power_state(cpunr) == 0))
>> +                               return 0; /* success: the CPU is halted */
>> +               }
>> +
>> +               /* Otherwise, wait and retry: */
>> +               msleep(1);
>> +       }
>> +
>> +       return -ETIMEDOUT; /* timeout */
>> +}
>> +
>> +static const struct mcpm_platform_ops exynos_power_ops = {
>> +       .power_up               = exynos_power_up,
>> +       .power_down             = exynos_power_down,
>> +       .power_down_finish      = exynos_power_down_finish,
>> +};
>> +
>> +static void __init exynos_mcpm_usage_count_init(void)
>> +{
>> +       unsigned int mpidr, cpu, cluster;
>> +
>> +       mpidr = read_cpuid_mpidr();
>> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       cpu_use_count[cpu][cluster] = 1;
>> +}
>> +
>> +/*
>> + * Enable cluster-level coherency, in preparation for turning on the MMU.
>> + */
>> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
>> +{
>> +       asm volatile ("\n"
>> +       "cmp    r0, #1\n"
>> +       "bxne   lr\n"
>> +       "b      cci_enable_port_for_self");
>> +}
>
> How many times are we going to duplicate this function before we decide
> to move it to a common header ?
I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
common function named "mcpm_default_power_up_setup" in the mcpm header
would be acceptable ?
>
>> +static int __init exynos_mcpm_init(void)
>> +{
>> +       int ret = 0;
>> +
>> +       if (!soc_is_exynos5420())
>> +               return -ENODEV;
>
> I do not particularly like these soc_is* stubs, but it is just a matter
> of taste.
Would you prefer a of_find_compatible_node check for exynos5420 ?

Will wait a day or two for more comments and then re-post.

Regards,
Abhilash
>
> Thanks,
> Lorenzo
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-29  3:32           ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-29  3:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lorenzo,

Thanks for the review.

[...]

>> +#include <linux/kernel.h>
>> +#include <linux/io.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/fs.h>
>> +#include <linux/delay.h>
>> +#include <linux/arm-cci.h>
>
> Alphabetical order please.
Will fix.

[...]
>> +#define exynos_v7_exit_coherency_flush(level) \
>> +       asm volatile( \
>> +       "stmfd  sp!, {fp, ip}\n\t"\
>> +       "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
>> +       "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
>> +       "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
>> +       "isb\n\t"\
>> +       "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
>> +       "clrex\n\t"\
>> +       "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
>> +       "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
>> +       /* Dummy Load of a device register to avoid Erratum 799270 */ \
>> +       "ldr    r4, [%0]\n\t" \
>> +       "and    r4, r4, #0\n\t" \
>> +       "orr    r0, r0, r4\n\t" \
>> +       "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
>> +       "isb\n\t" \
>> +       "dsb\n\t" \
>> +       "ldmfd  sp!, {fp, ip}" \
>> +       : \
>> +       : "Ir" (S5P_INFORM0) \
>> +       : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
>> +         "r9", "r10", "lr", "memory")
>> +
>
> Still investigating to see if can work around errata 799270 in a
> different fashion, will keep you posted.
Thanks.
>
>> +/*
>> + * We can't use regular spinlocks. In the switcher case, it is possible
>> + * for an outbound CPU to call power_down() after its inbound counterpart
>> + * is already live using the same logical CPU number which trips lockdep
>> + * debugging.
>> + */
>> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
>> +static int
>> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
>> +
>> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
>> +{
>> +       unsigned int tries = 100;
>> +       unsigned int val = 0;
>> +
>> +       if (enable) {
>> +               exynos_cluster_powerup(cluster);
>> +               val = S5P_CORE_LOCAL_PWR_EN;
>> +       } else {
>> +               exynos_cluster_powerdown(cluster);
>> +       }
>> +
>> +       /* Wait until cluster power control is applied */
>> +       while (tries--) {
>> +               if (exynos_cluster_power_state(cluster) == val)
>
> Do you really need val ?
Yes, val can be 0x0 or 0x3 depending on whether we want to enable or
disable the cluster.
>
>> +                       return 0;
>> +
>> +               cpu_relax();
>> +       }
>> +       pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
>> +               enable ? "on" : "off");
>> +
>> +       return -ETIMEDOUT;
>> +}
>> +
>> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
>> +{
>> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +       unsigned int err;
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +               cluster >= EXYNOS5420_NR_CLUSTERS)
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * Since this is called with IRQs enabled, and no arch_spin_lock_irq
>> +        * variant exists, we need to disable IRQs manually here.
>> +        */
>> +       local_irq_disable();
>> +       arch_spin_lock(&exynos_mcpm_lock);
>> +
>> +       cpu_use_count[cpu][cluster]++;
>> +       if (cpu_use_count[cpu][cluster] == 1) {
>> +               bool was_cluster_down =
>> +                       __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
>> +
>> +               /*
>> +                * Turn on the cluster (L2/COMMON) and then power on the cores.
>> +                * TODO: Turn off the clusters when all cores in the cluster
>> +                * are down to achieve significant power savings.
>> +                */
>> +               if (was_cluster_down) {
>> +                       err = exynos_cluster_power_control(cluster, 1);
>> +                       if (err) {
>> +                               exynos_cluster_power_control(cluster, 0);
>> +                               return err;
>
> You must not return without undoing what you should (irqs and locking).
Will do so.
>
>> +                       }
>> +               }
>> +
>> +               exynos_cpu_powerup(cpunr);
>> +
>> +               /* CPU should be powered up there */
>> +               /* Also setup Cluster Power Sequence here */
>
> Stale comment ?
Will remove.
>
>> +       } else if (cpu_use_count[cpu][cluster] != 2) {
>> +               /*
>> +                * The only possible values are:
>> +                * 0 = CPU down
>> +                * 1 = CPU (still) up
>> +                * 2 = CPU requested to be up before it had a chance
>> +                *     to actually make itself down.
>> +                * Any other value is a bug.
>> +                */
>> +               BUG();
>> +       }
>> +
>> +       arch_spin_unlock(&exynos_mcpm_lock);
>> +       local_irq_enable();
>> +
>> +       return 0;
>> +}
>> +
>> +static void exynos_power_down(void)
>> +{
>> +       unsigned int mpidr, cpu, cluster;
>> +       bool last_man = false, skip_wfi = false;
>> +       unsigned int cpunr;
>> +
>> +       mpidr = read_cpuid_mpidr();
>> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +       cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       __mcpm_cpu_going_down(cpu, cluster);
>> +
>> +       arch_spin_lock(&exynos_mcpm_lock);
>> +       BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
>> +       cpu_use_count[cpu][cluster]--;
>> +       if (cpu_use_count[cpu][cluster] == 0) {
>> +               int cnt = 0, i;
>> +
>> +               exynos_cpu_powerdown(cpunr);
>> +               for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
>> +                       cnt += cpu_use_count[i][cluster];
>> +               if (cnt == 0)
>> +                       last_man = true;
>
>                 for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
>                         if (cpu_use_count[i][cluster])
>                                 break;
>                 last_man = i == EXYNOS5420_CPUS_PER_CLUSTER;
>
> and get rid of cnt.
OK.
>
>> +       } else if (cpu_use_count[cpu][cluster] == 1) {
>> +               /*
>> +                * A power_up request went ahead of us.
>> +                * Even if we do not want to shut this CPU down,
>> +                * the caller expects a certain state as if the WFI
>> +                * was aborted.  So let's continue with cache cleaning.
>> +                */
>> +               skip_wfi = true;
>> +       } else {
>> +               BUG();
>> +       }
>> +
>> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +               /* Flush all cache levels for this cluster. */
>> +               exynos_v7_exit_coherency_flush(all);
>> +
>> +               /*
>> +                * Disable cluster-level coherency by masking
>> +                * incoming snoops and DVM messages:
>> +                */
>> +               cci_disable_port_by_cpu(mpidr);
>> +
>> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
>> +       } else {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +               /* Disable and flush the local CPU cache. */
>> +               exynos_v7_exit_coherency_flush(louis);
>> +       }
>> +
>> +       __mcpm_cpu_down(cpu, cluster);
>> +
>> +       /* Now we are prepared for power-down, do it: */
>> +       if (!skip_wfi)
>> +               wfi();
>> +
>> +       /* Not dead at this point?  Let our caller cope. */
>> +}
>> +
>> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
>> +{
>> +       unsigned int tries = 100;
>> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       /* Wait for the core state to be OFF */
>> +       while (tries--) {
>> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
>> +                       if ((exynos_cpu_power_state(cpunr) == 0))
>> +                               return 0; /* success: the CPU is halted */
>> +               }
>> +
>> +               /* Otherwise, wait and retry: */
>> +               msleep(1);
>> +       }
>> +
>> +       return -ETIMEDOUT; /* timeout */
>> +}
>> +
>> +static const struct mcpm_platform_ops exynos_power_ops = {
>> +       .power_up               = exynos_power_up,
>> +       .power_down             = exynos_power_down,
>> +       .power_down_finish      = exynos_power_down_finish,
>> +};
>> +
>> +static void __init exynos_mcpm_usage_count_init(void)
>> +{
>> +       unsigned int mpidr, cpu, cluster;
>> +
>> +       mpidr = read_cpuid_mpidr();
>> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       cpu_use_count[cpu][cluster] = 1;
>> +}
>> +
>> +/*
>> + * Enable cluster-level coherency, in preparation for turning on the MMU.
>> + */
>> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
>> +{
>> +       asm volatile ("\n"
>> +       "cmp    r0, #1\n"
>> +       "bxne   lr\n"
>> +       "b      cci_enable_port_for_self");
>> +}
>
> How many times are we going to duplicate this function before we decide
> to move it to a common header ?
I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
common function named "mcpm_default_power_up_setup" in the mcpm header
would be acceptable ?
>
>> +static int __init exynos_mcpm_init(void)
>> +{
>> +       int ret = 0;
>> +
>> +       if (!soc_is_exynos5420())
>> +               return -ENODEV;
>
> I do not particularly like these soc_is* stubs, but it is just a matter
> of taste.
Would you prefer a of_find_compatible_node check for exynos5420 ?

Will wait a day or two for more comments and then re-post.

Regards,
Abhilash
>
> Thanks,
> Lorenzo
>

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-29  3:32           ` Abhilash Kesavan
@ 2014-04-29 18:49               ` Nicolas Pitre
  -1 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-04-29 18:49 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: Lorenzo Pieralisi, Dave P Martin,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, arnd-r2nGTMty4D4

On Tue, 29 Apr 2014, Abhilash Kesavan wrote:

> >> +/*
> >> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> >> + */
> >> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> >> +{
> >> +       asm volatile ("\n"
> >> +       "cmp    r0, #1\n"
> >> +       "bxne   lr\n"
> >> +       "b      cci_enable_port_for_self");
> >> +}
> >
> > How many times are we going to duplicate this function before we decide
> > to move it to a common header ?
> I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
> copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
> common function named "mcpm_default_power_up_setup" in the mcpm header
> would be acceptable ?

Not necessarily.

First of all, this can't be a static inline as we need a pointer to it.  
And moving this to a header would create multiple instances of the same 
function in a multiplatform build for example.

Furthermore, this can't be called "default_power_up_setup" as this is 
specific to systems with a CCI.

It is true that the code in dcscb_setup.S does the same thing as this 
3-line inline assembly, but the former is heavily commented and may 
serve as an example template for platforms that may require something 
more sophisticated here.

There are other patterns that seem to emerge as more MCPM backends are 
being submitted.  I'm making a list of them and I intend to address such 
duplications after those backends do hit mainline.


Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-29 18:49               ` Nicolas Pitre
  0 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-04-29 18:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 29 Apr 2014, Abhilash Kesavan wrote:

> >> +/*
> >> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> >> + */
> >> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> >> +{
> >> +       asm volatile ("\n"
> >> +       "cmp    r0, #1\n"
> >> +       "bxne   lr\n"
> >> +       "b      cci_enable_port_for_self");
> >> +}
> >
> > How many times are we going to duplicate this function before we decide
> > to move it to a common header ?
> I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
> copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
> common function named "mcpm_default_power_up_setup" in the mcpm header
> would be acceptable ?

Not necessarily.

First of all, this can't be a static inline as we need a pointer to it.  
And moving this to a header would create multiple instances of the same 
function in a multiplatform build for example.

Furthermore, this can't be called "default_power_up_setup" as this is 
specific to systems with a CCI.

It is true that the code in dcscb_setup.S does the same thing as this 
3-line inline assembly, but the former is heavily commented and may 
serve as an example template for platforms that may require something 
more sophisticated here.

There are other patterns that seem to emerge as more MCPM backends are 
being submitted.  I'm making a list of them and I intend to address such 
duplications after those backends do hit mainline.


Nicolas

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-29 18:49               ` Nicolas Pitre
@ 2014-04-30  3:01                   ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-30  3:01 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Lorenzo Pieralisi, Dave P Martin,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, arnd-r2nGTMty4D4

Hi Nicolas,

On Wed, Apr 30, 2014 at 12:19 AM, Nicolas Pitre
<nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> On Tue, 29 Apr 2014, Abhilash Kesavan wrote:
>
>> >> +/*
>> >> + * Enable cluster-level coherency, in preparation for turning on the MMU.
>> >> + */
>> >> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
>> >> +{
>> >> +       asm volatile ("\n"
>> >> +       "cmp    r0, #1\n"
>> >> +       "bxne   lr\n"
>> >> +       "b      cci_enable_port_for_self");
>> >> +}
>> >
>> > How many times are we going to duplicate this function before we decide
>> > to move it to a common header ?
>> I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
>> copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
>> common function named "mcpm_default_power_up_setup" in the mcpm header
>> would be acceptable ?
>
> Not necessarily.
>
> First of all, this can't be a static inline as we need a pointer to it.
> And moving this to a header would create multiple instances of the same
> function in a multiplatform build for example.
>
> Furthermore, this can't be called "default_power_up_setup" as this is
> specific to systems with a CCI.
>
> It is true that the code in dcscb_setup.S does the same thing as this
> 3-line inline assembly, but the former is heavily commented and may
> serve as an example template for platforms that may require something
> more sophisticated here.
>
> There are other patterns that seem to emerge as more MCPM backends are
> being submitted.  I'm making a list of them and I intend to address such
> duplications after those backends do hit mainline.
OK. I'll keep the power_up_setup code in the exynos mcpm backend as it is.
Are there any other comments that you have or should I re-post a new
version that handles Lorenzo's comments.

Regards,
Abhilash
>
>
> Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-30  3:01                   ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-04-30  3:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nicolas,

On Wed, Apr 30, 2014 at 12:19 AM, Nicolas Pitre
<nicolas.pitre@linaro.org> wrote:
> On Tue, 29 Apr 2014, Abhilash Kesavan wrote:
>
>> >> +/*
>> >> + * Enable cluster-level coherency, in preparation for turning on the MMU.
>> >> + */
>> >> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
>> >> +{
>> >> +       asm volatile ("\n"
>> >> +       "cmp    r0, #1\n"
>> >> +       "bxne   lr\n"
>> >> +       "b      cci_enable_port_for_self");
>> >> +}
>> >
>> > How many times are we going to duplicate this function before we decide
>> > to move it to a common header ?
>> I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
>> copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
>> common function named "mcpm_default_power_up_setup" in the mcpm header
>> would be acceptable ?
>
> Not necessarily.
>
> First of all, this can't be a static inline as we need a pointer to it.
> And moving this to a header would create multiple instances of the same
> function in a multiplatform build for example.
>
> Furthermore, this can't be called "default_power_up_setup" as this is
> specific to systems with a CCI.
>
> It is true that the code in dcscb_setup.S does the same thing as this
> 3-line inline assembly, but the former is heavily commented and may
> serve as an example template for platforms that may require something
> more sophisticated here.
>
> There are other patterns that seem to emerge as more MCPM backends are
> being submitted.  I'm making a list of them and I intend to address such
> duplications after those backends do hit mainline.
OK. I'll keep the power_up_setup code in the exynos mcpm backend as it is.
Are there any other comments that you have or should I re-post a new
version that handles Lorenzo's comments.

Regards,
Abhilash
>
>
> Nicolas

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-30  3:01                   ` Abhilash Kesavan
@ 2014-04-30 10:24                       ` Dave Martin
  -1 siblings, 0 replies; 60+ messages in thread
From: Dave Martin @ 2014-04-30 10:24 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: Nicolas Pitre, Lorenzo Pieralisi,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, arnd-r2nGTMty4D4

On Wed, Apr 30, 2014 at 04:01:24AM +0100, Abhilash Kesavan wrote:
> Hi Nicolas,
> 
> On Wed, Apr 30, 2014 at 12:19 AM, Nicolas Pitre
> <nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> > On Tue, 29 Apr 2014, Abhilash Kesavan wrote:
> >
> >> >> +/*
> >> >> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> >> >> + */
> >> >> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> >> >> +{
> >> >> +       asm volatile ("\n"
> >> >> +       "cmp    r0, #1\n"
> >> >> +       "bxne   lr\n"
> >> >> +       "b      cci_enable_port_for_self");
> >> >> +}
> >> >
> >> > How many times are we going to duplicate this function before we decide
> >> > to move it to a common header ?
> >> I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
> >> copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
> >> common function named "mcpm_default_power_up_setup" in the mcpm header
> >> would be acceptable ?
> >
> > Not necessarily.
> >
> > First of all, this can't be a static inline as we need a pointer to it.
> > And moving this to a header would create multiple instances of the same
> > function in a multiplatform build for example.
> >
> > Furthermore, this can't be called "default_power_up_setup" as this is
> > specific to systems with a CCI.

On some SoCs the argument to cmp might not be #1, or the constant required
might not even be the same on all CPUs.  Some SoCs might need to do other
setup too, such as invalidating a cluster-level cache that doesn't power
up into a clean state.

So, the above function is going to be common but it's not really generic.

For such a tiny function, I agree that factoring it may not be that
beneficial.

Cheers
---Dave
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-30 10:24                       ` Dave Martin
  0 siblings, 0 replies; 60+ messages in thread
From: Dave Martin @ 2014-04-30 10:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 30, 2014 at 04:01:24AM +0100, Abhilash Kesavan wrote:
> Hi Nicolas,
> 
> On Wed, Apr 30, 2014 at 12:19 AM, Nicolas Pitre
> <nicolas.pitre@linaro.org> wrote:
> > On Tue, 29 Apr 2014, Abhilash Kesavan wrote:
> >
> >> >> +/*
> >> >> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> >> >> + */
> >> >> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> >> >> +{
> >> >> +       asm volatile ("\n"
> >> >> +       "cmp    r0, #1\n"
> >> >> +       "bxne   lr\n"
> >> >> +       "b      cci_enable_port_for_self");
> >> >> +}
> >> >
> >> > How many times are we going to duplicate this function before we decide
> >> > to move it to a common header ?
> >> I see this being used in arch/arm/mach-vexpress/tc2_pm.c (where I
> >> copied it from for exynos) and arch/arm/mach-vexpress/dcscb.c. A
> >> common function named "mcpm_default_power_up_setup" in the mcpm header
> >> would be acceptable ?
> >
> > Not necessarily.
> >
> > First of all, this can't be a static inline as we need a pointer to it.
> > And moving this to a header would create multiple instances of the same
> > function in a multiplatform build for example.
> >
> > Furthermore, this can't be called "default_power_up_setup" as this is
> > specific to systems with a CCI.

On some SoCs the argument to cmp might not be #1, or the constant required
might not even be the same on all CPUs.  Some SoCs might need to do other
setup too, such as invalidating a cluster-level cache that doesn't power
up into a clean state.

So, the above function is going to be common but it's not really generic.

For such a tiny function, I agree that factoring it may not be that
beneficial.

Cheers
---Dave

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-04-30 14:43         ` Nicolas Pitre
  -1 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-04-30 14:43 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: Dave.Martin-5wv7dgnIgG8, lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland-5wv7dgnIgG8,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

On Sat, 26 Apr 2014, Abhilash Kesavan wrote:

> Add machine-dependent MCPM call-backs for Exynos5420. These are used
> to power up/down the secondary CPUs during boot, shutdown, s2r and
> switching.
> 
> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

Small comments below.

> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
> +{
> +	unsigned int tries = 100;
> +	unsigned int val = 0;
> +
> +	if (enable) {
> +		exynos_cluster_powerup(cluster);
> +		val = S5P_CORE_LOCAL_PWR_EN;
> +	} else {
> +		exynos_cluster_powerdown(cluster);

It would be clearer if you have "val = 0" here instead so it looks 
symetric.

> +	}
> +
> +	/* Wait until cluster power control is applied */
> +	while (tries--) {
> +		if (exynos_cluster_power_state(cluster) == val)
> +			return 0;
> +
> +		cpu_relax();
> +	}
> +	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
> +		enable ? "on" : "off");
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
> +{
> +	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +	unsigned int err;
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +		cluster >= EXYNOS5420_NR_CLUSTERS)
> +		return -EINVAL;
> +
> +	/*
> +	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
> +	 * variant exists, we need to disable IRQs manually here.
> +	 */
> +	local_irq_disable();
> +	arch_spin_lock(&exynos_mcpm_lock);
> +
> +	cpu_use_count[cpu][cluster]++;
> +	if (cpu_use_count[cpu][cluster] == 1) {
> +		bool was_cluster_down =
> +			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;
> +
> +		/*
> +		 * Turn on the cluster (L2/COMMON) and then power on the cores.
> +		 * TODO: Turn off the clusters when all cores in the cluster
> +		 * are down to achieve significant power savings.
> +		 */

This TODO comment should be moved in exynos_power_down() were last_man 
is determined to be true.

> +		if (was_cluster_down) {
> +			err = exynos_cluster_power_control(cluster, 1);
> +			if (err) {
> +				exynos_cluster_power_control(cluster, 0);
> +				return err;

The lock is still held.

To make the code clearer, you should do:

			if (!err)
				exynos_cpu_powerup(cpunr);

and return err at the end.

> +			}
> +		}
> +
> +		exynos_cpu_powerup(cpunr);
> +
> +		/* CPU should be powered up there */
> +		/* Also setup Cluster Power Sequence here */

Both comments are wrong.  The CPU is not necessarily powered up yet at 
this point, and "Cluster Power Sequence" (whatever that is) should not 
happen here but in the callback provided to mcpm_sync_init().

> +	} else if (cpu_use_count[cpu][cluster] != 2) {
> +		/*
> +		 * The only possible values are:
> +		 * 0 = CPU down
> +		 * 1 = CPU (still) up
> +		 * 2 = CPU requested to be up before it had a chance
> +		 *     to actually make itself down.
> +		 * Any other value is a bug.
> +		 */
> +		BUG();
> +	}
> +
> +	arch_spin_unlock(&exynos_mcpm_lock);
> +	local_irq_enable();
> +
> +	return 0;
> +}
> +
> +static void exynos_power_down(void)
> +{
> +	unsigned int mpidr, cpu, cluster;
> +	bool last_man = false, skip_wfi = false;
> +	unsigned int cpunr;
> +
> +	mpidr = read_cpuid_mpidr();
> +	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +			cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +	__mcpm_cpu_going_down(cpu, cluster);
> +
> +	arch_spin_lock(&exynos_mcpm_lock);
> +	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +	cpu_use_count[cpu][cluster]--;
> +	if (cpu_use_count[cpu][cluster] == 0) {
> +		int cnt = 0, i;
> +
> +		exynos_cpu_powerdown(cpunr);
> +		for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
> +			cnt += cpu_use_count[i][cluster];
> +		if (cnt == 0)
> +			last_man = true;

I think Lorenzo commented on this code block already.

Otherwise it is almost there.


Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-30 14:43         ` Nicolas Pitre
  0 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-04-30 14:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, 26 Apr 2014, Abhilash Kesavan wrote:

> Add machine-dependent MCPM call-backs for Exynos5420. These are used
> to power up/down the secondary CPUs during boot, shutdown, s2r and
> switching.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>

Small comments below.

> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
> +{
> +	unsigned int tries = 100;
> +	unsigned int val = 0;
> +
> +	if (enable) {
> +		exynos_cluster_powerup(cluster);
> +		val = S5P_CORE_LOCAL_PWR_EN;
> +	} else {
> +		exynos_cluster_powerdown(cluster);

It would be clearer if you have "val = 0" here instead so it looks 
symetric.

> +	}
> +
> +	/* Wait until cluster power control is applied */
> +	while (tries--) {
> +		if (exynos_cluster_power_state(cluster) == val)
> +			return 0;
> +
> +		cpu_relax();
> +	}
> +	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
> +		enable ? "on" : "off");
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
> +{
> +	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +	unsigned int err;
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +		cluster >= EXYNOS5420_NR_CLUSTERS)
> +		return -EINVAL;
> +
> +	/*
> +	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
> +	 * variant exists, we need to disable IRQs manually here.
> +	 */
> +	local_irq_disable();
> +	arch_spin_lock(&exynos_mcpm_lock);
> +
> +	cpu_use_count[cpu][cluster]++;
> +	if (cpu_use_count[cpu][cluster] == 1) {
> +		bool was_cluster_down =
> +			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;
> +
> +		/*
> +		 * Turn on the cluster (L2/COMMON) and then power on the cores.
> +		 * TODO: Turn off the clusters when all cores in the cluster
> +		 * are down to achieve significant power savings.
> +		 */

This TODO comment should be moved in exynos_power_down() were last_man 
is determined to be true.

> +		if (was_cluster_down) {
> +			err = exynos_cluster_power_control(cluster, 1);
> +			if (err) {
> +				exynos_cluster_power_control(cluster, 0);
> +				return err;

The lock is still held.

To make the code clearer, you should do:

			if (!err)
				exynos_cpu_powerup(cpunr);

and return err at the end.

> +			}
> +		}
> +
> +		exynos_cpu_powerup(cpunr);
> +
> +		/* CPU should be powered up there */
> +		/* Also setup Cluster Power Sequence here */

Both comments are wrong.  The CPU is not necessarily powered up yet at 
this point, and "Cluster Power Sequence" (whatever that is) should not 
happen here but in the callback provided to mcpm_sync_init().

> +	} else if (cpu_use_count[cpu][cluster] != 2) {
> +		/*
> +		 * The only possible values are:
> +		 * 0 = CPU down
> +		 * 1 = CPU (still) up
> +		 * 2 = CPU requested to be up before it had a chance
> +		 *     to actually make itself down.
> +		 * Any other value is a bug.
> +		 */
> +		BUG();
> +	}
> +
> +	arch_spin_unlock(&exynos_mcpm_lock);
> +	local_irq_enable();
> +
> +	return 0;
> +}
> +
> +static void exynos_power_down(void)
> +{
> +	unsigned int mpidr, cpu, cluster;
> +	bool last_man = false, skip_wfi = false;
> +	unsigned int cpunr;
> +
> +	mpidr = read_cpuid_mpidr();
> +	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +			cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +	__mcpm_cpu_going_down(cpu, cluster);
> +
> +	arch_spin_lock(&exynos_mcpm_lock);
> +	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +	cpu_use_count[cpu][cluster]--;
> +	if (cpu_use_count[cpu][cluster] == 0) {
> +		int cnt = 0, i;
> +
> +		exynos_cpu_powerdown(cpunr);
> +		for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
> +			cnt += cpu_use_count[i][cluster];
> +		if (cnt == 0)
> +			last_man = true;

I think Lorenzo commented on this code block already.

Otherwise it is almost there.


Nicolas

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

* Re: [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
  2014-04-28 12:49             ` Abhilash Kesavan
@ 2014-04-30 14:49                 ` Nicolas Pitre
  -1 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-04-30 14:49 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: Daniel Lezcano, Dave Martin, Lorenzo Pieralisi, linux-arm-kernel,
	Kukjin Kim, Tomasz Figa, Andrew Bresticker, Thomas P Abraham,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland, devicetree,
	Grant Likely, robh+dt, Will Deacon, Arnd Bergmann

On Mon, 28 Apr 2014, Abhilash Kesavan wrote:

> On Mon, Apr 28, 2014 at 4:55 PM, Daniel Lezcano
> <daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> > On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
> >>
> >> Add a user interface to check the core and cluster status on
> >> Exynos5420. This can be utilized while debugging mcpm issues.
> >> cat /dev/bL_status will show the current power status of all
> >> the 8 cores along with the cluster.
> >>
> >> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> >> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> ---
> >
> >
> > Hi Abhilash,
> 
> Hi Daniel,
> >
> > I don't think you should add this file.
> >
> > 1. big Little is not exynos specific
> But the core control/status bits that I am accessing are exynos
> specific and currently it is being enabled only on 5420.

Maybe yt is not worth pushing this patch upstream?  Once basic debugging 
is over, you shouldn't have to use this code anymore.


Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
@ 2014-04-30 14:49                 ` Nicolas Pitre
  0 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-04-30 14:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 28 Apr 2014, Abhilash Kesavan wrote:

> On Mon, Apr 28, 2014 at 4:55 PM, Daniel Lezcano
> <daniel.lezcano@linaro.org> wrote:
> > On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
> >>
> >> Add a user interface to check the core and cluster status on
> >> Exynos5420. This can be utilized while debugging mcpm issues.
> >> cat /dev/bL_status will show the current power status of all
> >> the 8 cores along with the cluster.
> >>
> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> >> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
> >> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> >> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> >> ---
> >
> >
> > Hi Abhilash,
> 
> Hi Daniel,
> >
> > I don't think you should add this file.
> >
> > 1. big Little is not exynos specific
> But the core control/status bits that I am accessing are exynos
> specific and currently it is being enabled only on 5420.

Maybe yt is not worth pushing this patch upstream?  Once basic debugging 
is over, you shouldn't have to use this code anymore.


Nicolas

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-04-30 14:59         ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 60+ messages in thread
From: Lorenzo Pieralisi @ 2014-04-30 14:59 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave P Martin,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, arnd-r2nGTMty4D4,
	kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

On Sat, Apr 26, 2014 at 05:05:47PM +0100, Abhilash Kesavan wrote:

[...]

> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +

I missed it on first review, but you do need to disable L2 prefetching
on A15 here as we do in TC2 (tc2_pm.c), this power down procedure is not
compliant otherwise.

Thanks,
Lorenzo

> +               /* Flush all cache levels for this cluster. */
> +               exynos_v7_exit_coherency_flush(all);
> +
> +               /*
> +                * Disable cluster-level coherency by masking
> +                * incoming snoops and DVM messages:
> +                */
> +               cci_disable_port_by_cpu(mpidr);
> +
> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> +       } else {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +
> +               /* Disable and flush the local CPU cache. */
> +               exynos_v7_exit_coherency_flush(louis);
> +       }
> +
> +       __mcpm_cpu_down(cpu, cluster);
> +
> +       /* Now we are prepared for power-down, do it: */
> +       if (!skip_wfi)
> +               wfi();
> +
> +       /* Not dead at this point?  Let our caller cope. */
> +}
> +
> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
> +{
> +       unsigned int tries = 100;
> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       /* Wait for the core state to be OFF */
> +       while (tries--) {
> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
> +                       if ((exynos_cpu_power_state(cpunr) == 0))
> +                               return 0; /* success: the CPU is halted */
> +               }
> +
> +               /* Otherwise, wait and retry: */
> +               msleep(1);
> +       }
> +
> +       return -ETIMEDOUT; /* timeout */
> +}
> +
> +static const struct mcpm_platform_ops exynos_power_ops = {
> +       .power_up               = exynos_power_up,
> +       .power_down             = exynos_power_down,
> +       .power_down_finish      = exynos_power_down_finish,
> +};
> +
> +static void __init exynos_mcpm_usage_count_init(void)
> +{
> +       unsigned int mpidr, cpu, cluster;
> +
> +       mpidr = read_cpuid_mpidr();
> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       cpu_use_count[cpu][cluster] = 1;
> +}
> +
> +/*
> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> + */
> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> +{
> +       asm volatile ("\n"
> +       "cmp    r0, #1\n"
> +       "bxne   lr\n"
> +       "b      cci_enable_port_for_self");
> +}
> +
> +static int __init exynos_mcpm_init(void)
> +{
> +       int ret = 0;
> +
> +       if (!soc_is_exynos5420())
> +               return -ENODEV;
> +
> +       if (!cci_probed())
> +               return -ENODEV;
> +
> +       /*
> +        * To increase the stability of KFC reset we need to program
> +        * the PMU SPARE3 register
> +        */
> +       __raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
> +
> +       exynos_mcpm_usage_count_init();
> +
> +       ret = mcpm_platform_register(&exynos_power_ops);
> +       if (!ret)
> +               ret = mcpm_sync_init(exynos_pm_power_up_setup);
> +       if (ret)
> +               return ret;
> +
> +       mcpm_smp_set_ops();
> +
> +       pr_info("Exynos MCPM support installed\n");
> +
> +       /*
> +        * Future entries into the kernel can now go
> +        * through the cluster entry vectors.
> +        */
> +       __raw_writel(virt_to_phys(mcpm_entry_point),
> +               REG_ENTRY_ADDR);
> +
> +       return ret;
> +}
> +
> +early_initcall(exynos_mcpm_init);
> diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
> index 6685ebf..f44d318 100644
> --- a/arch/arm/mach-exynos/regs-pmu.h
> +++ b/arch/arm/mach-exynos/regs-pmu.h
> @@ -38,6 +38,7 @@
>  #define S5P_INFORM5                            S5P_PMUREG(0x0814)
>  #define S5P_INFORM6                            S5P_PMUREG(0x0818)
>  #define S5P_INFORM7                            S5P_PMUREG(0x081C)
> +#define S5P_PMU_SPARE3                         S5P_PMUREG(0x090C)
> 
>  #define S5P_ARM_CORE0_LOWPWR                   S5P_PMUREG(0x1000)
>  #define S5P_DIS_IRQ_CORE0                      S5P_PMUREG(0x1004)
> @@ -325,4 +326,6 @@
> 
>  #define EXYNOS5_OPTION_USE_RETENTION                           (1 << 4)
> 
> +#define EXYNOS5420_SWRESET_KFC_SEL                             0x3
> +
>  #endif /* __ASM_ARCH_REGS_PMU_H */
> --
> 1.8.3.2
> 
> 

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

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-04-30 14:59         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 60+ messages in thread
From: Lorenzo Pieralisi @ 2014-04-30 14:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 26, 2014 at 05:05:47PM +0100, Abhilash Kesavan wrote:

[...]

> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +

I missed it on first review, but you do need to disable L2 prefetching
on A15 here as we do in TC2 (tc2_pm.c), this power down procedure is not
compliant otherwise.

Thanks,
Lorenzo

> +               /* Flush all cache levels for this cluster. */
> +               exynos_v7_exit_coherency_flush(all);
> +
> +               /*
> +                * Disable cluster-level coherency by masking
> +                * incoming snoops and DVM messages:
> +                */
> +               cci_disable_port_by_cpu(mpidr);
> +
> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> +       } else {
> +               arch_spin_unlock(&exynos_mcpm_lock);
> +
> +               /* Disable and flush the local CPU cache. */
> +               exynos_v7_exit_coherency_flush(louis);
> +       }
> +
> +       __mcpm_cpu_down(cpu, cluster);
> +
> +       /* Now we are prepared for power-down, do it: */
> +       if (!skip_wfi)
> +               wfi();
> +
> +       /* Not dead at this point?  Let our caller cope. */
> +}
> +
> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
> +{
> +       unsigned int tries = 100;
> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       /* Wait for the core state to be OFF */
> +       while (tries--) {
> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
> +                       if ((exynos_cpu_power_state(cpunr) == 0))
> +                               return 0; /* success: the CPU is halted */
> +               }
> +
> +               /* Otherwise, wait and retry: */
> +               msleep(1);
> +       }
> +
> +       return -ETIMEDOUT; /* timeout */
> +}
> +
> +static const struct mcpm_platform_ops exynos_power_ops = {
> +       .power_up               = exynos_power_up,
> +       .power_down             = exynos_power_down,
> +       .power_down_finish      = exynos_power_down_finish,
> +};
> +
> +static void __init exynos_mcpm_usage_count_init(void)
> +{
> +       unsigned int mpidr, cpu, cluster;
> +
> +       mpidr = read_cpuid_mpidr();
> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +       cpu_use_count[cpu][cluster] = 1;
> +}
> +
> +/*
> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> + */
> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
> +{
> +       asm volatile ("\n"
> +       "cmp    r0, #1\n"
> +       "bxne   lr\n"
> +       "b      cci_enable_port_for_self");
> +}
> +
> +static int __init exynos_mcpm_init(void)
> +{
> +       int ret = 0;
> +
> +       if (!soc_is_exynos5420())
> +               return -ENODEV;
> +
> +       if (!cci_probed())
> +               return -ENODEV;
> +
> +       /*
> +        * To increase the stability of KFC reset we need to program
> +        * the PMU SPARE3 register
> +        */
> +       __raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
> +
> +       exynos_mcpm_usage_count_init();
> +
> +       ret = mcpm_platform_register(&exynos_power_ops);
> +       if (!ret)
> +               ret = mcpm_sync_init(exynos_pm_power_up_setup);
> +       if (ret)
> +               return ret;
> +
> +       mcpm_smp_set_ops();
> +
> +       pr_info("Exynos MCPM support installed\n");
> +
> +       /*
> +        * Future entries into the kernel can now go
> +        * through the cluster entry vectors.
> +        */
> +       __raw_writel(virt_to_phys(mcpm_entry_point),
> +               REG_ENTRY_ADDR);
> +
> +       return ret;
> +}
> +
> +early_initcall(exynos_mcpm_init);
> diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
> index 6685ebf..f44d318 100644
> --- a/arch/arm/mach-exynos/regs-pmu.h
> +++ b/arch/arm/mach-exynos/regs-pmu.h
> @@ -38,6 +38,7 @@
>  #define S5P_INFORM5                            S5P_PMUREG(0x0814)
>  #define S5P_INFORM6                            S5P_PMUREG(0x0818)
>  #define S5P_INFORM7                            S5P_PMUREG(0x081C)
> +#define S5P_PMU_SPARE3                         S5P_PMUREG(0x090C)
> 
>  #define S5P_ARM_CORE0_LOWPWR                   S5P_PMUREG(0x1000)
>  #define S5P_DIS_IRQ_CORE0                      S5P_PMUREG(0x1004)
> @@ -325,4 +326,6 @@
> 
>  #define EXYNOS5_OPTION_USE_RETENTION                           (1 << 4)
> 
> +#define EXYNOS5420_SWRESET_KFC_SEL                             0x3
> +
>  #endif /* __ASM_ARCH_REGS_PMU_H */
> --
> 1.8.3.2
> 
> 

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

* Re: [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
  2014-04-30 14:49                 ` Nicolas Pitre
@ 2014-05-01  9:39                     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-01  9:39 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Daniel Lezcano, Dave Martin, Lorenzo Pieralisi, linux-arm-kernel,
	Kukjin Kim, Tomasz Figa, Andrew Bresticker, Thomas P Abraham,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland, devicetree,
	Grant Likely, robh+dt, Will Deacon, Arnd Bergmann

Hi Nicolas,

On Wed, Apr 30, 2014 at 8:19 PM, Nicolas Pitre <nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> On Mon, 28 Apr 2014, Abhilash Kesavan wrote:
>
>> On Mon, Apr 28, 2014 at 4:55 PM, Daniel Lezcano
>> <daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>> > On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
>> >>
>> >> Add a user interface to check the core and cluster status on
>> >> Exynos5420. This can be utilized while debugging mcpm issues.
>> >> cat /dev/bL_status will show the current power status of all
>> >> the 8 cores along with the cluster.
>> >>
>> >> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> >> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> >> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> >> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> >> ---
>> >
>> >
>> > Hi Abhilash,
>>
>> Hi Daniel,
>> >
>> > I don't think you should add this file.
>> >
>> > 1. big Little is not exynos specific
>> But the core control/status bits that I am accessing are exynos
>> specific and currently it is being enabled only on 5420.
>
> Maybe yt is not worth pushing this patch upstream?  Once basic debugging
> is over, you shouldn't have to use this code anymore.
OK, will drop this patch.

Regards,
Abhilash
>
>
> Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420
@ 2014-05-01  9:39                     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-01  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nicolas,

On Wed, Apr 30, 2014 at 8:19 PM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> On Mon, 28 Apr 2014, Abhilash Kesavan wrote:
>
>> On Mon, Apr 28, 2014 at 4:55 PM, Daniel Lezcano
>> <daniel.lezcano@linaro.org> wrote:
>> > On 04/26/2014 06:05 PM, Abhilash Kesavan wrote:
>> >>
>> >> Add a user interface to check the core and cluster status on
>> >> Exynos5420. This can be utilized while debugging mcpm issues.
>> >> cat /dev/bL_status will show the current power status of all
>> >> the 8 cores along with the cluster.
>> >>
>> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
>> >> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> >> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>> >> ---
>> >
>> >
>> > Hi Abhilash,
>>
>> Hi Daniel,
>> >
>> > I don't think you should add this file.
>> >
>> > 1. big Little is not exynos specific
>> But the core control/status bits that I am accessing are exynos
>> specific and currently it is being enabled only on 5420.
>
> Maybe yt is not worth pushing this patch upstream?  Once basic debugging
> is over, you shouldn't have to use this code anymore.
OK, will drop this patch.

Regards,
Abhilash
>
>
> Nicolas

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-30 14:43         ` Nicolas Pitre
@ 2014-05-01  9:39             ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-01  9:39 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Dave Martin, Lorenzo Pieralisi, Daniel Lezcano, linux-arm-kernel,
	Kukjin Kim, Tomasz Figa, Andrew Bresticker, Thomas P Abraham,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland, devicetree,
	Grant Likely, robh+dt, Will Deacon, Arnd Bergmann

Hi Nicolas,

On Wed, Apr 30, 2014 at 8:13 PM, Nicolas Pitre <nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> On Sat, 26 Apr 2014, Abhilash Kesavan wrote:
>
>> Add machine-dependent MCPM call-backs for Exynos5420. These are used
>> to power up/down the secondary CPUs during boot, shutdown, s2r and
>> switching.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>
> Small comments below.
>
>> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
>> +{
>> +     unsigned int tries = 100;
>> +     unsigned int val = 0;
>> +
>> +     if (enable) {
>> +             exynos_cluster_powerup(cluster);
>> +             val = S5P_CORE_LOCAL_PWR_EN;
>> +     } else {
>> +             exynos_cluster_powerdown(cluster);
>
> It would be clearer if you have "val = 0" here instead so it looks
> symetric.
OK.
>
>> +     }
>> +
>> +     /* Wait until cluster power control is applied */
>> +     while (tries--) {
>> +             if (exynos_cluster_power_state(cluster) == val)
>> +                     return 0;
>> +
>> +             cpu_relax();
>> +     }
>> +     pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
>> +             enable ? "on" : "off");
>> +
>> +     return -ETIMEDOUT;
>> +}
>> +
>> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
>> +{
>> +     unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +     unsigned int err;
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +             cluster >= EXYNOS5420_NR_CLUSTERS)
>> +             return -EINVAL;
>> +
>> +     /*
>> +      * Since this is called with IRQs enabled, and no arch_spin_lock_irq
>> +      * variant exists, we need to disable IRQs manually here.
>> +      */
>> +     local_irq_disable();
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +
>> +     cpu_use_count[cpu][cluster]++;
>> +     if (cpu_use_count[cpu][cluster] == 1) {
>> +             bool was_cluster_down =
>> +                     __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
>> +
>> +             /*
>> +              * Turn on the cluster (L2/COMMON) and then power on the cores.
>> +              * TODO: Turn off the clusters when all cores in the cluster
>> +              * are down to achieve significant power savings.
>> +              */
>
> This TODO comment should be moved in exynos_power_down() were last_man
> is determined to be true.
Will move the comment.
>
>> +             if (was_cluster_down) {
>> +                     err = exynos_cluster_power_control(cluster, 1);
>> +                     if (err) {
>> +                             exynos_cluster_power_control(cluster, 0);
>> +                             return err;
>
> The lock is still held.
>
> To make the code clearer, you should do:
>
>                         if (!err)
>                                 exynos_cpu_powerup(cpunr);
>
> and return err at the end.
OK.
>
>> +                     }
>> +             }
>> +
>> +             exynos_cpu_powerup(cpunr);
>> +
>> +             /* CPU should be powered up there */
>> +             /* Also setup Cluster Power Sequence here */
>
> Both comments are wrong.  The CPU is not necessarily powered up yet at
> this point, and "Cluster Power Sequence" (whatever that is) should not
> happen here but in the callback provided to mcpm_sync_init().
Have removed these.
>
>> +     } else if (cpu_use_count[cpu][cluster] != 2) {
>> +             /*
>> +              * The only possible values are:
>> +              * 0 = CPU down
>> +              * 1 = CPU (still) up
>> +              * 2 = CPU requested to be up before it had a chance
>> +              *     to actually make itself down.
>> +              * Any other value is a bug.
>> +              */
>> +             BUG();
>> +     }
>> +
>> +     arch_spin_unlock(&exynos_mcpm_lock);
>> +     local_irq_enable();
>> +
>> +     return 0;
>> +}
>> +
>> +static void exynos_power_down(void)
>> +{
>> +     unsigned int mpidr, cpu, cluster;
>> +     bool last_man = false, skip_wfi = false;
>> +     unsigned int cpunr;
>> +
>> +     mpidr = read_cpuid_mpidr();
>> +     cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +     cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +     cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                     cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +     __mcpm_cpu_going_down(cpu, cluster);
>> +
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +     BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
>> +     cpu_use_count[cpu][cluster]--;
>> +     if (cpu_use_count[cpu][cluster] == 0) {
>> +             int cnt = 0, i;
>> +
>> +             exynos_cpu_powerdown(cpunr);
>> +             for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
>> +                     cnt += cpu_use_count[i][cluster];
>> +             if (cnt == 0)
>> +                     last_man = true;
>
> I think Lorenzo commented on this code block already.
>
> Otherwise it is almost there.
>
Thanks,
Abhilash
>
> Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-05-01  9:39             ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-01  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nicolas,

On Wed, Apr 30, 2014 at 8:13 PM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> On Sat, 26 Apr 2014, Abhilash Kesavan wrote:
>
>> Add machine-dependent MCPM call-backs for Exynos5420. These are used
>> to power up/down the secondary CPUs during boot, shutdown, s2r and
>> switching.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>
> Small comments below.
>
>> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
>> +{
>> +     unsigned int tries = 100;
>> +     unsigned int val = 0;
>> +
>> +     if (enable) {
>> +             exynos_cluster_powerup(cluster);
>> +             val = S5P_CORE_LOCAL_PWR_EN;
>> +     } else {
>> +             exynos_cluster_powerdown(cluster);
>
> It would be clearer if you have "val = 0" here instead so it looks
> symetric.
OK.
>
>> +     }
>> +
>> +     /* Wait until cluster power control is applied */
>> +     while (tries--) {
>> +             if (exynos_cluster_power_state(cluster) == val)
>> +                     return 0;
>> +
>> +             cpu_relax();
>> +     }
>> +     pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
>> +             enable ? "on" : "off");
>> +
>> +     return -ETIMEDOUT;
>> +}
>> +
>> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
>> +{
>> +     unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +     unsigned int err;
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +             cluster >= EXYNOS5420_NR_CLUSTERS)
>> +             return -EINVAL;
>> +
>> +     /*
>> +      * Since this is called with IRQs enabled, and no arch_spin_lock_irq
>> +      * variant exists, we need to disable IRQs manually here.
>> +      */
>> +     local_irq_disable();
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +
>> +     cpu_use_count[cpu][cluster]++;
>> +     if (cpu_use_count[cpu][cluster] == 1) {
>> +             bool was_cluster_down =
>> +                     __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
>> +
>> +             /*
>> +              * Turn on the cluster (L2/COMMON) and then power on the cores.
>> +              * TODO: Turn off the clusters when all cores in the cluster
>> +              * are down to achieve significant power savings.
>> +              */
>
> This TODO comment should be moved in exynos_power_down() were last_man
> is determined to be true.
Will move the comment.
>
>> +             if (was_cluster_down) {
>> +                     err = exynos_cluster_power_control(cluster, 1);
>> +                     if (err) {
>> +                             exynos_cluster_power_control(cluster, 0);
>> +                             return err;
>
> The lock is still held.
>
> To make the code clearer, you should do:
>
>                         if (!err)
>                                 exynos_cpu_powerup(cpunr);
>
> and return err at the end.
OK.
>
>> +                     }
>> +             }
>> +
>> +             exynos_cpu_powerup(cpunr);
>> +
>> +             /* CPU should be powered up there */
>> +             /* Also setup Cluster Power Sequence here */
>
> Both comments are wrong.  The CPU is not necessarily powered up yet at
> this point, and "Cluster Power Sequence" (whatever that is) should not
> happen here but in the callback provided to mcpm_sync_init().
Have removed these.
>
>> +     } else if (cpu_use_count[cpu][cluster] != 2) {
>> +             /*
>> +              * The only possible values are:
>> +              * 0 = CPU down
>> +              * 1 = CPU (still) up
>> +              * 2 = CPU requested to be up before it had a chance
>> +              *     to actually make itself down.
>> +              * Any other value is a bug.
>> +              */
>> +             BUG();
>> +     }
>> +
>> +     arch_spin_unlock(&exynos_mcpm_lock);
>> +     local_irq_enable();
>> +
>> +     return 0;
>> +}
>> +
>> +static void exynos_power_down(void)
>> +{
>> +     unsigned int mpidr, cpu, cluster;
>> +     bool last_man = false, skip_wfi = false;
>> +     unsigned int cpunr;
>> +
>> +     mpidr = read_cpuid_mpidr();
>> +     cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +     cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +     cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                     cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +     __mcpm_cpu_going_down(cpu, cluster);
>> +
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +     BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
>> +     cpu_use_count[cpu][cluster]--;
>> +     if (cpu_use_count[cpu][cluster] == 0) {
>> +             int cnt = 0, i;
>> +
>> +             exynos_cpu_powerdown(cpunr);
>> +             for (i = 0; i < EXYNOS5420_CPUS_PER_CLUSTER; i++)
>> +                     cnt += cpu_use_count[i][cluster];
>> +             if (cnt == 0)
>> +                     last_man = true;
>
> I think Lorenzo commented on this code block already.
>
> Otherwise it is almost there.
>
Thanks,
Abhilash
>
> Nicolas

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

* Re: [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
  2014-04-30 14:59         ` Lorenzo Pieralisi
@ 2014-05-01  9:39             ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-01  9:39 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave P Martin,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, arnd-r2nGTMty4D4

Hi Lorenzo,

On Wed, Apr 30, 2014 at 8:29 PM, Lorenzo Pieralisi
<lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org> wrote:
> On Sat, Apr 26, 2014 at 05:05:47PM +0100, Abhilash Kesavan wrote:
>
> [...]
>
>> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>
> I missed it on first review, but you do need to disable L2 prefetching
> on A15 here as we do in TC2 (tc2_pm.c), this power down procedure is not
> compliant otherwise.
OK, I see this as being part of the power down sequence described in
A15 TRM, will add.

Regards,
Abhilash
>
> Thanks,
> Lorenzo
>
>> +               /* Flush all cache levels for this cluster. */
>> +               exynos_v7_exit_coherency_flush(all);
>> +
>> +               /*
>> +                * Disable cluster-level coherency by masking
>> +                * incoming snoops and DVM messages:
>> +                */
>> +               cci_disable_port_by_cpu(mpidr);
>> +
>> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
>> +       } else {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +               /* Disable and flush the local CPU cache. */
>> +               exynos_v7_exit_coherency_flush(louis);
>> +       }
>> +
>> +       __mcpm_cpu_down(cpu, cluster);
>> +
>> +       /* Now we are prepared for power-down, do it: */
>> +       if (!skip_wfi)
>> +               wfi();
>> +
>> +       /* Not dead at this point?  Let our caller cope. */
>> +}
>> +
>> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
>> +{
>> +       unsigned int tries = 100;
>> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       /* Wait for the core state to be OFF */
>> +       while (tries--) {
>> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
>> +                       if ((exynos_cpu_power_state(cpunr) == 0))
>> +                               return 0; /* success: the CPU is halted */
>> +               }
>> +
>> +               /* Otherwise, wait and retry: */
>> +               msleep(1);
>> +       }
>> +
>> +       return -ETIMEDOUT; /* timeout */
>> +}
>> +
>> +static const struct mcpm_platform_ops exynos_power_ops = {
>> +       .power_up               = exynos_power_up,
>> +       .power_down             = exynos_power_down,
>> +       .power_down_finish      = exynos_power_down_finish,
>> +};
>> +
>> +static void __init exynos_mcpm_usage_count_init(void)
>> +{
>> +       unsigned int mpidr, cpu, cluster;
>> +
>> +       mpidr = read_cpuid_mpidr();
>> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       cpu_use_count[cpu][cluster] = 1;
>> +}
>> +
>> +/*
>> + * Enable cluster-level coherency, in preparation for turning on the MMU.
>> + */
>> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
>> +{
>> +       asm volatile ("\n"
>> +       "cmp    r0, #1\n"
>> +       "bxne   lr\n"
>> +       "b      cci_enable_port_for_self");
>> +}
>> +
>> +static int __init exynos_mcpm_init(void)
>> +{
>> +       int ret = 0;
>> +
>> +       if (!soc_is_exynos5420())
>> +               return -ENODEV;
>> +
>> +       if (!cci_probed())
>> +               return -ENODEV;
>> +
>> +       /*
>> +        * To increase the stability of KFC reset we need to program
>> +        * the PMU SPARE3 register
>> +        */
>> +       __raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
>> +
>> +       exynos_mcpm_usage_count_init();
>> +
>> +       ret = mcpm_platform_register(&exynos_power_ops);
>> +       if (!ret)
>> +               ret = mcpm_sync_init(exynos_pm_power_up_setup);
>> +       if (ret)
>> +               return ret;
>> +
>> +       mcpm_smp_set_ops();
>> +
>> +       pr_info("Exynos MCPM support installed\n");
>> +
>> +       /*
>> +        * Future entries into the kernel can now go
>> +        * through the cluster entry vectors.
>> +        */
>> +       __raw_writel(virt_to_phys(mcpm_entry_point),
>> +               REG_ENTRY_ADDR);
>> +
>> +       return ret;
>> +}
>> +
>> +early_initcall(exynos_mcpm_init);
>> diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
>> index 6685ebf..f44d318 100644
>> --- a/arch/arm/mach-exynos/regs-pmu.h
>> +++ b/arch/arm/mach-exynos/regs-pmu.h
>> @@ -38,6 +38,7 @@
>>  #define S5P_INFORM5                            S5P_PMUREG(0x0814)
>>  #define S5P_INFORM6                            S5P_PMUREG(0x0818)
>>  #define S5P_INFORM7                            S5P_PMUREG(0x081C)
>> +#define S5P_PMU_SPARE3                         S5P_PMUREG(0x090C)
>>
>>  #define S5P_ARM_CORE0_LOWPWR                   S5P_PMUREG(0x1000)
>>  #define S5P_DIS_IRQ_CORE0                      S5P_PMUREG(0x1004)
>> @@ -325,4 +326,6 @@
>>
>>  #define EXYNOS5_OPTION_USE_RETENTION                           (1 << 4)
>>
>> +#define EXYNOS5420_SWRESET_KFC_SEL                             0x3
>> +
>>  #endif /* __ASM_ARCH_REGS_PMU_H */
>> --
>> 1.8.3.2
>>
>>
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions
@ 2014-05-01  9:39             ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-01  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Lorenzo,

On Wed, Apr 30, 2014 at 8:29 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On Sat, Apr 26, 2014 at 05:05:47PM +0100, Abhilash Kesavan wrote:
>
> [...]
>
>> +       if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>
> I missed it on first review, but you do need to disable L2 prefetching
> on A15 here as we do in TC2 (tc2_pm.c), this power down procedure is not
> compliant otherwise.
OK, I see this as being part of the power down sequence described in
A15 TRM, will add.

Regards,
Abhilash
>
> Thanks,
> Lorenzo
>
>> +               /* Flush all cache levels for this cluster. */
>> +               exynos_v7_exit_coherency_flush(all);
>> +
>> +               /*
>> +                * Disable cluster-level coherency by masking
>> +                * incoming snoops and DVM messages:
>> +                */
>> +               cci_disable_port_by_cpu(mpidr);
>> +
>> +               __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
>> +       } else {
>> +               arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +               /* Disable and flush the local CPU cache. */
>> +               exynos_v7_exit_coherency_flush(louis);
>> +       }
>> +
>> +       __mcpm_cpu_down(cpu, cluster);
>> +
>> +       /* Now we are prepared for power-down, do it: */
>> +       if (!skip_wfi)
>> +               wfi();
>> +
>> +       /* Not dead at this point?  Let our caller cope. */
>> +}
>> +
>> +static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
>> +{
>> +       unsigned int tries = 100;
>> +       unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       /* Wait for the core state to be OFF */
>> +       while (tries--) {
>> +               if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
>> +                       if ((exynos_cpu_power_state(cpunr) == 0))
>> +                               return 0; /* success: the CPU is halted */
>> +               }
>> +
>> +               /* Otherwise, wait and retry: */
>> +               msleep(1);
>> +       }
>> +
>> +       return -ETIMEDOUT; /* timeout */
>> +}
>> +
>> +static const struct mcpm_platform_ops exynos_power_ops = {
>> +       .power_up               = exynos_power_up,
>> +       .power_down             = exynos_power_down,
>> +       .power_down_finish      = exynos_power_down_finish,
>> +};
>> +
>> +static void __init exynos_mcpm_usage_count_init(void)
>> +{
>> +       unsigned int mpidr, cpu, cluster;
>> +
>> +       mpidr = read_cpuid_mpidr();
>> +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +
>> +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +       BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
>> +                       cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +       cpu_use_count[cpu][cluster] = 1;
>> +}
>> +
>> +/*
>> + * Enable cluster-level coherency, in preparation for turning on the MMU.
>> + */
>> +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
>> +{
>> +       asm volatile ("\n"
>> +       "cmp    r0, #1\n"
>> +       "bxne   lr\n"
>> +       "b      cci_enable_port_for_self");
>> +}
>> +
>> +static int __init exynos_mcpm_init(void)
>> +{
>> +       int ret = 0;
>> +
>> +       if (!soc_is_exynos5420())
>> +               return -ENODEV;
>> +
>> +       if (!cci_probed())
>> +               return -ENODEV;
>> +
>> +       /*
>> +        * To increase the stability of KFC reset we need to program
>> +        * the PMU SPARE3 register
>> +        */
>> +       __raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
>> +
>> +       exynos_mcpm_usage_count_init();
>> +
>> +       ret = mcpm_platform_register(&exynos_power_ops);
>> +       if (!ret)
>> +               ret = mcpm_sync_init(exynos_pm_power_up_setup);
>> +       if (ret)
>> +               return ret;
>> +
>> +       mcpm_smp_set_ops();
>> +
>> +       pr_info("Exynos MCPM support installed\n");
>> +
>> +       /*
>> +        * Future entries into the kernel can now go
>> +        * through the cluster entry vectors.
>> +        */
>> +       __raw_writel(virt_to_phys(mcpm_entry_point),
>> +               REG_ENTRY_ADDR);
>> +
>> +       return ret;
>> +}
>> +
>> +early_initcall(exynos_mcpm_init);
>> diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
>> index 6685ebf..f44d318 100644
>> --- a/arch/arm/mach-exynos/regs-pmu.h
>> +++ b/arch/arm/mach-exynos/regs-pmu.h
>> @@ -38,6 +38,7 @@
>>  #define S5P_INFORM5                            S5P_PMUREG(0x0814)
>>  #define S5P_INFORM6                            S5P_PMUREG(0x0818)
>>  #define S5P_INFORM7                            S5P_PMUREG(0x081C)
>> +#define S5P_PMU_SPARE3                         S5P_PMUREG(0x090C)
>>
>>  #define S5P_ARM_CORE0_LOWPWR                   S5P_PMUREG(0x1000)
>>  #define S5P_DIS_IRQ_CORE0                      S5P_PMUREG(0x1004)
>> @@ -325,4 +326,6 @@
>>
>>  #define EXYNOS5_OPTION_USE_RETENTION                           (1 << 4)
>>
>> +#define EXYNOS5420_SWRESET_KFC_SEL                             0x3
>> +
>>  #endif /* __ASM_ARCH_REGS_PMU_H */
>> --
>> 1.8.3.2
>>
>>
>

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

* [PATCH v4 0/5] MCPM backend for Exynos5420
  2014-04-26 16:05 ` Abhilash Kesavan
@ 2014-05-02 15:24     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:24 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

This is v4 of the series adding MCPM backend support for SMP secondary boot
and core switching on Samsung's Exynos5420. The patches are based on the mcpm
support added for Exynos5420 in the Chromium kernel repository here:
https://chromium.googlesource.com/chromiumos/third_party/kernel-next/+/chromeos-3.8

This patchset depends on:
- [v2,1/2] ARM: EXYNOS: Map SYSRAM through generic SRAM bindings
(https://patchwork.kernel.org/patch/4101091/)

The patches have been prepared on linux-next(20140501) and tested on SMDK5420
EVT1 using the "/dev/b.L_switcher" user interface. Secondary core boot-up has
also been tested on an Exynos5420-based chromebook.

Changes since v3:
	- Rebased on top of the latest SYSRAM DT patchset from Sachin Kamat.

Addressed the following comments from Lorenzo Pieralisi and Nicolas Pitre:
	- Dropped the patch "arm: exynos: Add /dev/bL_status user interface on
	  Exynos5420".
	- Fixed the header ordering and removed unnecessary header inclusions.
	- Made the enable/disable code for cluster power symmetric.
	- Fixed the error path in exynos_power_up.
	- Got rid of "cnt" variable used for last man checking.
	- Removed stale comments.
	- Replaced "soc_is" with "of_find_compatible_node" check for exynos5420.
	- Added L2 prefetching disable code for A15 power down from tc2_pm.c.

Changes since v2:
Addressed the following comments from Nicolas Pitre and Daniel Lezcano:
	- Added generic common (cluster) configuration functions to pm.c
	  which may be used by other subsystems.
	- Removed unused "cpumask" variable in mcpm code.
	- Re-worked exynos_power_down_finish() referencing the tc2_pm code.
	- Removed the status checks in core and cluster power functions. We
	  just set the power control bit and do not check the previous state
	  anymore.
	- Removed incorrect jiffies timeout usage in path where IRQs are
	  disabled.

Changes since v1:
Addressed the following comments from Dave Martin and Nicolas Pitre:
	- Fixed help text for EXYNOS5420_MCPM symbol.
	- Removed mcpm-exynos-setup.S file and added similar code from tc2_pm.c.
	- Changed the spinlock name from "bl_lock" to "exynos_mcpm_lock".
	- Removed snoop enable/disable calls due to possible cpuidle issue and
	  not having numbers proving a significant power savings. Dropped the
	  "drivers/bus: arm-cci: Add common control interface for ACE ports"
	  patch from v1 as it was no longer needed.
	- Created a macro for exynos-specific v7_exit_coherency_flush which
	  handles an erratum. This was done to prevent duplication of code.
	- Removed "outer_flush_all" call.
	- Removed redundant dsb in power_down function.
	- Removed unnecessary initialization of global variables to zero.
	- Split the /dev/bL_status debug interface into another patch.
	- Fixed error handling in exynos_mcpm_init().
	- Called mcpm_smp_set_ops directly from exynos_mcpm_init().
	- Added a TODO for supporting cluster down on exynos5420.

NOTE:
- Have added Leela Krishna's generic cpu power control function series
  as part of this patchset.
- Only the patch "arm: exynos: Add MCPM call-back functions" has changed
  from v3.
- I have tested with and without the erratum 799270 workaround and both
  work fine. I have kept the erratum fix for the time being.

Abhilash Kesavan (2):
  arm: exynos: Add generic cluster power control functions
  arm: exynos: Add MCPM call-back functions

Andrew Bresticker (1):
  ARM: dts: exynos5420: add CCI node

Leela Krishna Amudala (2):
  ARM: EXYNOS: Add generic cpu power control functions for all exynos
    based SoCs
  ARM: EXYNOS: use generic exynos cpu power control functions

 arch/arm/boot/dts/exynos5420.dtsi  |   27 +++
 arch/arm/mach-exynos/Kconfig       |    8 +
 arch/arm/mach-exynos/Makefile      |    2 +
 arch/arm/mach-exynos/common.h      |    6 +
 arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/platsmp.c     |    9 +-
 arch/arm/mach-exynos/pm.c          |   66 +++++++
 arch/arm/mach-exynos/regs-pmu.h    |   15 ++
 8 files changed, 472 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

-- 
1.7.9.5

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

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

* [PATCH v4 0/5] MCPM backend for Exynos5420
@ 2014-05-02 15:24     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

This is v4 of the series adding MCPM backend support for SMP secondary boot
and core switching on Samsung's Exynos5420. The patches are based on the mcpm
support added for Exynos5420 in the Chromium kernel repository here:
https://chromium.googlesource.com/chromiumos/third_party/kernel-next/+/chromeos-3.8

This patchset depends on:
- [v2,1/2] ARM: EXYNOS: Map SYSRAM through generic SRAM bindings
(https://patchwork.kernel.org/patch/4101091/)

The patches have been prepared on linux-next(20140501) and tested on SMDK5420
EVT1 using the "/dev/b.L_switcher" user interface. Secondary core boot-up has
also been tested on an Exynos5420-based chromebook.

Changes since v3:
	- Rebased on top of the latest SYSRAM DT patchset from Sachin Kamat.

Addressed the following comments from Lorenzo Pieralisi and Nicolas Pitre:
	- Dropped the patch "arm: exynos: Add /dev/bL_status user interface on
	  Exynos5420".
	- Fixed the header ordering and removed unnecessary header inclusions.
	- Made the enable/disable code for cluster power symmetric.
	- Fixed the error path in exynos_power_up.
	- Got rid of "cnt" variable used for last man checking.
	- Removed stale comments.
	- Replaced "soc_is" with "of_find_compatible_node" check for exynos5420.
	- Added L2 prefetching disable code for A15 power down from tc2_pm.c.

Changes since v2:
Addressed the following comments from Nicolas Pitre and Daniel Lezcano:
	- Added generic common (cluster) configuration functions to pm.c
	  which may be used by other subsystems.
	- Removed unused "cpumask" variable in mcpm code.
	- Re-worked exynos_power_down_finish() referencing the tc2_pm code.
	- Removed the status checks in core and cluster power functions. We
	  just set the power control bit and do not check the previous state
	  anymore.
	- Removed incorrect jiffies timeout usage in path where IRQs are
	  disabled.

Changes since v1:
Addressed the following comments from Dave Martin and Nicolas Pitre:
	- Fixed help text for EXYNOS5420_MCPM symbol.
	- Removed mcpm-exynos-setup.S file and added similar code from tc2_pm.c.
	- Changed the spinlock name from "bl_lock" to "exynos_mcpm_lock".
	- Removed snoop enable/disable calls due to possible cpuidle issue and
	  not having numbers proving a significant power savings. Dropped the
	  "drivers/bus: arm-cci: Add common control interface for ACE ports"
	  patch from v1 as it was no longer needed.
	- Created a macro for exynos-specific v7_exit_coherency_flush which
	  handles an erratum. This was done to prevent duplication of code.
	- Removed "outer_flush_all" call.
	- Removed redundant dsb in power_down function.
	- Removed unnecessary initialization of global variables to zero.
	- Split the /dev/bL_status debug interface into another patch.
	- Fixed error handling in exynos_mcpm_init().
	- Called mcpm_smp_set_ops directly from exynos_mcpm_init().
	- Added a TODO for supporting cluster down on exynos5420.

NOTE:
- Have added Leela Krishna's generic cpu power control function series
  as part of this patchset.
- Only the patch "arm: exynos: Add MCPM call-back functions" has changed
  from v3.
- I have tested with and without the erratum 799270 workaround and both
  work fine. I have kept the erratum fix for the time being.

Abhilash Kesavan (2):
  arm: exynos: Add generic cluster power control functions
  arm: exynos: Add MCPM call-back functions

Andrew Bresticker (1):
  ARM: dts: exynos5420: add CCI node

Leela Krishna Amudala (2):
  ARM: EXYNOS: Add generic cpu power control functions for all exynos
    based SoCs
  ARM: EXYNOS: use generic exynos cpu power control functions

 arch/arm/boot/dts/exynos5420.dtsi  |   27 +++
 arch/arm/mach-exynos/Kconfig       |    8 +
 arch/arm/mach-exynos/Makefile      |    2 +
 arch/arm/mach-exynos/common.h      |    6 +
 arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/platsmp.c     |    9 +-
 arch/arm/mach-exynos/pm.c          |   66 +++++++
 arch/arm/mach-exynos/regs-pmu.h    |   15 ++
 8 files changed, 472 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

-- 
1.7.9.5

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

* [PATCH v4 2/5] ARM: EXYNOS: use generic exynos cpu power control functions
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-05-02 15:25         ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

From: Leela Krishna Amudala <leela.krishna-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

Use generic exynos cpu power control functions to power up/down
and to know the status of the cpu.

Signed-off-by: Leela Krishna Amudala <leela.krishna-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 arch/arm/mach-exynos/platsmp.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 0aac032..d442a66 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -130,15 +130,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 */
 	write_pen_release(phys_cpu);
 
-	if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
-		__raw_writel(S5P_CORE_LOCAL_PWR_EN,
-			     S5P_ARM_CORE1_CONFIGURATION);
-
+	if (!exynos_cpu_power_state(cpu)) {
+		exynos_cpu_powerup(cpu);
 		timeout = 10;
 
 		/* wait max 10 ms until cpu1 is on */
-		while ((__raw_readl(S5P_ARM_CORE1_STATUS)
-			& S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
+		while (exynos_cpu_power_state(cpu) != S5P_CORE_LOCAL_PWR_EN) {
 			if (timeout-- == 0)
 				break;
 
-- 
1.7.9.5

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

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

* [PATCH v4 2/5] ARM: EXYNOS: use generic exynos cpu power control functions
@ 2014-05-02 15:25         ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

From: Leela Krishna Amudala <leela.krishna@linaro.org>

Use generic exynos cpu power control functions to power up/down
and to know the status of the cpu.

Signed-off-by: Leela Krishna Amudala <leela.krishna@linaro.org>
---
 arch/arm/mach-exynos/platsmp.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 0aac032..d442a66 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -130,15 +130,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
 	 */
 	write_pen_release(phys_cpu);
 
-	if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
-		__raw_writel(S5P_CORE_LOCAL_PWR_EN,
-			     S5P_ARM_CORE1_CONFIGURATION);
-
+	if (!exynos_cpu_power_state(cpu)) {
+		exynos_cpu_powerup(cpu);
 		timeout = 10;
 
 		/* wait max 10 ms until cpu1 is on */
-		while ((__raw_readl(S5P_ARM_CORE1_STATUS)
-			& S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
+		while (exynos_cpu_power_state(cpu) != S5P_CORE_LOCAL_PWR_EN) {
 			if (timeout-- == 0)
 				break;
 
-- 
1.7.9.5

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

* [PATCH v4 3/5] arm: exynos: Add generic cluster power control functions
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-05-02 15:25         ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

Add generic cluster power control functions for exynos based SoCS
for cluster power up/down and to know the cluster status.

Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/mach-exynos/common.h   |    3 +++
 arch/arm/mach-exynos/pm.c       |   30 ++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |    6 ++++++
 3 files changed, 39 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index a7dbb5f..03b8bb2 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -66,5 +66,8 @@ extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
 extern void exynos_cpu_powerdown(int cpu);
 extern void exynos_cpu_powerup(int cpu);
 extern int  exynos_cpu_power_state(int cpu);
+extern void exynos_cluster_powerdown(int cluster);
+extern void exynos_cluster_powerup(int cluster);
+extern int  exynos_cluster_power_state(int cluster);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 6651028..f02d864 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -136,6 +136,36 @@ int exynos_cpu_power_state(int cpu)
 			S5P_CORE_LOCAL_PWR_EN);
 }
 
+/**
+ * exynos_common_powerdown : power down the specified cluster
+ * @cluster : the cluster to power down
+ */
+void exynos_cluster_powerdown(int cluster)
+{
+	__raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_powerup : power up the specified cluster
+ * @cluster : the cluster to power up
+ */
+void exynos_cluster_powerup(int cluster)
+{
+	__raw_writel(S5P_CORE_LOCAL_PWR_EN,
+		     EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_power_state : returns the power state of the cluster
+ * @cluster : the cluster to retrieve the power state from
+ *
+ */
+int exynos_cluster_power_state(int cluster)
+{
+	return (__raw_readl(EXYNOS_COMMON_STATUS(cluster)) &
+			S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 0bdfcbc..6685ebf 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -127,6 +127,12 @@
 #define EXYNOS_ARM_CORE_STATUS(_nr)		\
 			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
 
+#define EXYNOS_ARM_COMMON_CONFIGURATION		S5P_PMUREG(0x2500)
+#define EXYNOS_COMMON_CONFIGURATION(_nr)	\
+			(EXYNOS_ARM_COMMON_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_COMMON_STATUS(_nr)		\
+			(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x4)
+
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154)
 #define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174)
-- 
1.7.9.5

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

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

* [PATCH v4 3/5] arm: exynos: Add generic cluster power control functions
@ 2014-05-02 15:25         ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

Add generic cluster power control functions for exynos based SoCS
for cluster power up/down and to know the cluster status.

Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/mach-exynos/common.h   |    3 +++
 arch/arm/mach-exynos/pm.c       |   30 ++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |    6 ++++++
 3 files changed, 39 insertions(+)

diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index a7dbb5f..03b8bb2 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -66,5 +66,8 @@ extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
 extern void exynos_cpu_powerdown(int cpu);
 extern void exynos_cpu_powerup(int cpu);
 extern int  exynos_cpu_power_state(int cpu);
+extern void exynos_cluster_powerdown(int cluster);
+extern void exynos_cluster_powerup(int cluster);
+extern int  exynos_cluster_power_state(int cluster);
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 6651028..f02d864 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -136,6 +136,36 @@ int exynos_cpu_power_state(int cpu)
 			S5P_CORE_LOCAL_PWR_EN);
 }
 
+/**
+ * exynos_common_powerdown : power down the specified cluster
+ * @cluster : the cluster to power down
+ */
+void exynos_cluster_powerdown(int cluster)
+{
+	__raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_powerup : power up the specified cluster
+ * @cluster : the cluster to power up
+ */
+void exynos_cluster_powerup(int cluster)
+{
+	__raw_writel(S5P_CORE_LOCAL_PWR_EN,
+		     EXYNOS_COMMON_CONFIGURATION(cluster));
+}
+
+/**
+ * exynos_cluster_power_state : returns the power state of the cluster
+ * @cluster : the cluster to retrieve the power state from
+ *
+ */
+int exynos_cluster_power_state(int cluster)
+{
+	return (__raw_readl(EXYNOS_COMMON_STATUS(cluster)) &
+			S5P_CORE_LOCAL_PWR_EN);
+}
+
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
 
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 0bdfcbc..6685ebf 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -127,6 +127,12 @@
 #define EXYNOS_ARM_CORE_STATUS(_nr)		\
 			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
 
+#define EXYNOS_ARM_COMMON_CONFIGURATION		S5P_PMUREG(0x2500)
+#define EXYNOS_COMMON_CONFIGURATION(_nr)	\
+			(EXYNOS_ARM_COMMON_CONFIGURATION + (0x80 * (_nr)))
+#define EXYNOS_COMMON_STATUS(_nr)		\
+			(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x4)
+
 /* Only for EXYNOS4210 */
 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154)
 #define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174)
-- 
1.7.9.5

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

* [PATCH v4 4/5] ARM: dts: exynos5420: add CCI node
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-05-02 15:25         ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

From: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

Add device-tree bindings for the ARM CCI-400 on Exynos5420.  There
are two slave interfaces: one for the A15 cluster and one for the
A7 cluster.

Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/boot/dts/exynos5420.dtsi |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index ff496ad..3140138 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -58,6 +58,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x0>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu1: cpu@1 {
@@ -65,6 +66,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x1>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu2: cpu@2 {
@@ -72,6 +74,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x2>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu3: cpu@3 {
@@ -79,6 +82,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x3>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu4: cpu@100 {
@@ -86,6 +90,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x100>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu5: cpu@101 {
@@ -93,6 +98,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x101>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu6: cpu@102 {
@@ -100,6 +106,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x102>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu7: cpu@103 {
@@ -107,6 +114,26 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x103>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
+		};
+	};
+
+	cci@10d20000 {
+		compatible = "arm,cci-400";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x10d20000 0x1000>;
+		ranges = <0x0 0x10d20000 0x6000>;
+
+		cci_control0: slave-if@4000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x4000 0x1000>;
+		};
+		cci_control1: slave-if@5000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x5000 0x1000>;
 		};
 	};
 
-- 
1.7.9.5

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

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

* [PATCH v4 4/5] ARM: dts: exynos5420: add CCI node
@ 2014-05-02 15:25         ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

From: Andrew Bresticker <abrestic@chromium.org>

Add device-tree bindings for the ARM CCI-400 on Exynos5420.  There
are two slave interfaces: one for the A15 cluster and one for the
A7 cluster.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/boot/dts/exynos5420.dtsi |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index ff496ad..3140138 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -58,6 +58,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x0>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu1: cpu at 1 {
@@ -65,6 +66,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x1>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu2: cpu at 2 {
@@ -72,6 +74,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x2>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu3: cpu at 3 {
@@ -79,6 +82,7 @@
 			compatible = "arm,cortex-a15";
 			reg = <0x3>;
 			clock-frequency = <1800000000>;
+			cci-control-port = <&cci_control1>;
 		};
 
 		cpu4: cpu at 100 {
@@ -86,6 +90,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x100>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu5: cpu at 101 {
@@ -93,6 +98,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x101>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu6: cpu at 102 {
@@ -100,6 +106,7 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x102>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
 		};
 
 		cpu7: cpu at 103 {
@@ -107,6 +114,26 @@
 			compatible = "arm,cortex-a7";
 			reg = <0x103>;
 			clock-frequency = <1000000000>;
+			cci-control-port = <&cci_control0>;
+		};
+	};
+
+	cci at 10d20000 {
+		compatible = "arm,cci-400";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x10d20000 0x1000>;
+		ranges = <0x0 0x10d20000 0x6000>;
+
+		cci_control0: slave-if at 4000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x4000 0x1000>;
+		};
+		cci_control1: slave-if at 5000 {
+			compatible = "arm,cci-400-ctrl-if";
+			interface-type = "ace";
+			reg = <0x5000 0x1000>;
 		};
 	};
 
-- 
1.7.9.5

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
  2014-04-26 16:05     ` Abhilash Kesavan
@ 2014-05-02 15:25         ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A, Dave.Martin-5wv7dgnIgG8,
	lorenzo.pieralisi-5wv7dgnIgG8,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	arnd-r2nGTMty4D4, kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

Add machine-dependent MCPM call-backs for Exynos5420. These are used
to power up/down the secondary CPUs during boot, shutdown, s2r and
switching.

Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/mach-exynos/Kconfig       |    8 +
 arch/arm/mach-exynos/Makefile      |    2 +
 arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h    |    3 +
 4 files changed, 358 insertions(+)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5c34dc2..138070e 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -73,4 +73,12 @@ config SOC_EXYNOS5440
 
 endmenu
 
+config EXYNOS5420_MCPM
+	bool "Exynos5420 Multi-Cluster PM support"
+	depends on MCPM && SOC_EXYNOS5420
+	select ARM_CCI
+	help
+	  This is needed to provide CPU and cluster power management
+	  on Exynos5420 implementing big.LITTLE.
+
 endif
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index a656dbe..01bc9b9 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= firmware.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec)
+
+obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
new file mode 100644
index 0000000..d0f7461
--- /dev/null
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * arch/arm/mach-exynos/mcpm-exynos.c
+ *
+ * Based on arch/arm/mach-vexpress/dcscb.c
+ *
+ * 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/arm-cci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+#include <asm/mcpm.h>
+
+#include "regs-pmu.h"
+#include "common.h"
+
+#define EXYNOS5420_CPUS_PER_CLUSTER	4
+#define EXYNOS5420_NR_CLUSTERS		2
+
+/* Non-secure iRAM base address */
+static void __iomem *ns_sram_base_addr;
+
+/*
+ * The common v7_exit_coherency_flush API could not be used because of the
+ * Erratum 799270 workaround. This macro is the same as the common one (in
+ * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
+ */
+#define exynos_v7_exit_coherency_flush(level) \
+	asm volatile( \
+	"stmfd	sp!, {fp, ip}\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \
+	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \
+	"isb\n\t"\
+	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \
+	"clrex\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \
+	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \
+	/* Dummy Load of a device register to avoid Erratum 799270 */ \
+	"ldr	r4, [%0]\n\t" \
+	"and	r4, r4, #0\n\t" \
+	"orr	r0, r0, r4\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \
+	"isb\n\t" \
+	"dsb\n\t" \
+	"ldmfd	sp!, {fp, ip}" \
+	: \
+	: "Ir" (S5P_INFORM0) \
+	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+	  "r9", "r10", "lr", "memory")
+
+/*
+ * We can't use regular spinlocks. In the switcher case, it is possible
+ * for an outbound CPU to call power_down() after its inbound counterpart
+ * is already live using the same logical CPU number which trips lockdep
+ * debugging.
+ */
+static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+static int
+cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
+
+#define exynos_cluster_unused(cluster) \
+	(!cpu_use_count[0][cluster] && \
+	 !cpu_use_count[1][cluster] && \
+	 !cpu_use_count[2][cluster] && \
+	 !cpu_use_count[3][cluster])
+
+static int exynos_cluster_power_control(unsigned int cluster, int enable)
+{
+	unsigned int tries = 100;
+	unsigned int val;
+
+	if (enable) {
+		exynos_cluster_powerup(cluster);
+		val = S5P_CORE_LOCAL_PWR_EN;
+	} else {
+		exynos_cluster_powerdown(cluster);
+		val = 0;
+	}
+
+	/* Wait until cluster power control is applied */
+	while (tries--) {
+		if (exynos_cluster_power_state(cluster) == val)
+			return 0;
+
+		cpu_relax();
+	}
+	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
+		enable ? "on" : "off");
+
+	return -ETIMEDOUT;
+}
+
+static int exynos_power_up(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+	int err = 0;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+		cluster >= EXYNOS5420_NR_CLUSTERS)
+		return -EINVAL;
+
+	/*
+	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
+	 * variant exists, we need to disable IRQs manually here.
+	 */
+	local_irq_disable();
+	arch_spin_lock(&exynos_mcpm_lock);
+
+	cpu_use_count[cpu][cluster]++;
+	if (cpu_use_count[cpu][cluster] == 1) {
+		bool was_cluster_down =
+			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;
+
+		/*
+		 * Turn on the cluster (L2/COMMON) and then power on the
+		 * cores.
+		 */
+		if (was_cluster_down)
+			err = exynos_cluster_power_control(cluster, 1);
+
+		if (!err)
+			exynos_cpu_powerup(cpunr);
+		else
+			exynos_cluster_power_control(cluster, 0);
+	} else if (cpu_use_count[cpu][cluster] != 2) {
+		/*
+		 * The only possible values are:
+		 * 0 = CPU down
+		 * 1 = CPU (still) up
+		 * 2 = CPU requested to be up before it had a chance
+		 *     to actually make itself down.
+		 * Any other value is a bug.
+		 */
+		BUG();
+	}
+
+	arch_spin_unlock(&exynos_mcpm_lock);
+	local_irq_enable();
+
+	return err;
+}
+
+static void exynos_power_down(void)
+{
+	unsigned int mpidr, cpu, cluster;
+	bool last_man = false, skip_wfi = false;
+	unsigned int cpunr;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	__mcpm_cpu_going_down(cpu, cluster);
+
+	arch_spin_lock(&exynos_mcpm_lock);
+	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+	cpu_use_count[cpu][cluster]--;
+	if (cpu_use_count[cpu][cluster] == 0) {
+		exynos_cpu_powerdown(cpunr);
+
+		if (exynos_cluster_unused(cluster))
+			last_man = true;
+	} else if (cpu_use_count[cpu][cluster] == 1) {
+		/*
+		 * A power_up request went ahead of us.
+		 * Even if we do not want to shut this CPU down,
+		 * the caller expects a certain state as if the WFI
+		 * was aborted.  So let's continue with cache cleaning.
+		 */
+		skip_wfi = true;
+	} else {
+		BUG();
+	}
+
+	/*
+	 * TODO: Turn off the clusters when all cores in the cluster
+	 * are down to achieve significant power savings.
+	 */
+	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		/* Flush all cache levels for this cluster. */
+		exynos_v7_exit_coherency_flush(all);
+
+		/*
+		 * Disable cluster-level coherency by masking
+		 * incoming snoops and DVM messages:
+		 */
+		cci_disable_port_by_cpu(mpidr);
+
+		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
+	} else {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
+			/*
+			 * On the Cortex-A15 we need to disable
+			 * L2 prefetching before flushing the cache.
+			 */
+			asm volatile(
+			"mcr	p15, 1, %0, c15, c0, 3\n\t"
+			"isb\n\t"
+			"dsb"
+			: : "r" (0x400));
+		}
+
+		/* Disable and flush the local CPU cache. */
+		exynos_v7_exit_coherency_flush(louis);
+	}
+
+	__mcpm_cpu_down(cpu, cluster);
+
+	/* Now we are prepared for power-down, do it: */
+	if (!skip_wfi)
+		wfi();
+
+	/* Not dead at this point?  Let our caller cope. */
+}
+
+static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int tries = 100;
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	/* Wait for the core state to be OFF */
+	while (tries--) {
+		if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
+			if ((exynos_cpu_power_state(cpunr) == 0))
+				return 0; /* success: the CPU is halted */
+		}
+
+		/* Otherwise, wait and retry: */
+		msleep(1);
+	}
+
+	return -ETIMEDOUT; /* timeout */
+}
+
+static const struct mcpm_platform_ops exynos_power_ops = {
+	.power_up		= exynos_power_up,
+	.power_down		= exynos_power_down,
+	.power_down_finish	= exynos_power_down_finish,
+};
+
+static void __init exynos_mcpm_usage_count_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	cpu_use_count[cpu][cluster] = 1;
+}
+
+/*
+ * Enable cluster-level coherency, in preparation for turning on the MMU.
+ */
+static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
+{
+	asm volatile ("\n"
+	"cmp	r0, #1\n"
+	"bxne	lr\n"
+	"b	cci_enable_port_for_self");
+}
+
+static int __init exynos_mcpm_init(void)
+{
+	struct device_node *node;
+	int ret = 0;
+
+	node = of_find_compatible_node(NULL, NULL, "samsung,exynos5420");
+	if (!node)
+		return -ENODEV;
+	of_node_put(node);
+
+	if (!cci_probed())
+		return -ENODEV;
+
+	node = of_find_compatible_node(NULL, NULL,
+			"samsung,exynos4210-sram-ns");
+	if (!node)
+		return -ENODEV;
+
+	ns_sram_base_addr = of_iomap(node, 0);
+	of_node_put(node);
+	if (!ns_sram_base_addr) {
+		pr_err("failed to map non-secure iRAM base address\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * To increase the stability of KFC reset we need to program
+	 * the PMU SPARE3 register
+	 */
+	__raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
+
+	exynos_mcpm_usage_count_init();
+
+	ret = mcpm_platform_register(&exynos_power_ops);
+	if (!ret)
+		ret = mcpm_sync_init(exynos_pm_power_up_setup);
+	if (ret) {
+		iounmap(ns_sram_base_addr);
+		return ret;
+	}
+
+	mcpm_smp_set_ops();
+
+	pr_info("Exynos MCPM support installed\n");
+
+	/*
+	 * Future entries into the kernel can now go
+	 * through the cluster entry vectors.
+	 */
+	__raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 0x1c);
+
+	return ret;
+}
+
+early_initcall(exynos_mcpm_init);
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 6685ebf..f44d318 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -38,6 +38,7 @@
 #define S5P_INFORM5				S5P_PMUREG(0x0814)
 #define S5P_INFORM6				S5P_PMUREG(0x0818)
 #define S5P_INFORM7				S5P_PMUREG(0x081C)
+#define S5P_PMU_SPARE3				S5P_PMUREG(0x090C)
 
 #define S5P_ARM_CORE0_LOWPWR			S5P_PMUREG(0x1000)
 #define S5P_DIS_IRQ_CORE0			S5P_PMUREG(0x1004)
@@ -325,4 +326,6 @@
 
 #define EXYNOS5_OPTION_USE_RETENTION				(1 << 4)
 
+#define EXYNOS5420_SWRESET_KFC_SEL				0x3
+
 #endif /* __ASM_ARCH_REGS_PMU_H */
-- 
1.7.9.5

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

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
@ 2014-05-02 15:25         ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-02 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

Add machine-dependent MCPM call-backs for Exynos5420. These are used
to power up/down the secondary CPUs during boot, shutdown, s2r and
switching.

Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
 arch/arm/mach-exynos/Kconfig       |    8 +
 arch/arm/mach-exynos/Makefile      |    2 +
 arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h    |    3 +
 4 files changed, 358 insertions(+)
 create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 5c34dc2..138070e 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -73,4 +73,12 @@ config SOC_EXYNOS5440
 
 endmenu
 
+config EXYNOS5420_MCPM
+	bool "Exynos5420 Multi-Cluster PM support"
+	depends on MCPM && SOC_EXYNOS5420
+	select ARM_CCI
+	help
+	  This is needed to provide CPU and cluster power management
+	  on Exynos5420 implementing big.LITTLE.
+
 endif
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index a656dbe..01bc9b9 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= firmware.o
 
 plus_sec := $(call as-instr,.arch_extension sec,+sec)
 AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec)
+
+obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
new file mode 100644
index 0000000..d0f7461
--- /dev/null
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * arch/arm/mach-exynos/mcpm-exynos.c
+ *
+ * Based on arch/arm/mach-vexpress/dcscb.c
+ *
+ * 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/arm-cci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+#include <asm/mcpm.h>
+
+#include "regs-pmu.h"
+#include "common.h"
+
+#define EXYNOS5420_CPUS_PER_CLUSTER	4
+#define EXYNOS5420_NR_CLUSTERS		2
+
+/* Non-secure iRAM base address */
+static void __iomem *ns_sram_base_addr;
+
+/*
+ * The common v7_exit_coherency_flush API could not be used because of the
+ * Erratum 799270 workaround. This macro is the same as the common one (in
+ * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
+ */
+#define exynos_v7_exit_coherency_flush(level) \
+	asm volatile( \
+	"stmfd	sp!, {fp, ip}\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \
+	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \
+	"isb\n\t"\
+	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \
+	"clrex\n\t"\
+	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \
+	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \
+	/* Dummy Load of a device register to avoid Erratum 799270 */ \
+	"ldr	r4, [%0]\n\t" \
+	"and	r4, r4, #0\n\t" \
+	"orr	r0, r0, r4\n\t" \
+	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \
+	"isb\n\t" \
+	"dsb\n\t" \
+	"ldmfd	sp!, {fp, ip}" \
+	: \
+	: "Ir" (S5P_INFORM0) \
+	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+	  "r9", "r10", "lr", "memory")
+
+/*
+ * We can't use regular spinlocks. In the switcher case, it is possible
+ * for an outbound CPU to call power_down() after its inbound counterpart
+ * is already live using the same logical CPU number which trips lockdep
+ * debugging.
+ */
+static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+static int
+cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
+
+#define exynos_cluster_unused(cluster) \
+	(!cpu_use_count[0][cluster] && \
+	 !cpu_use_count[1][cluster] && \
+	 !cpu_use_count[2][cluster] && \
+	 !cpu_use_count[3][cluster])
+
+static int exynos_cluster_power_control(unsigned int cluster, int enable)
+{
+	unsigned int tries = 100;
+	unsigned int val;
+
+	if (enable) {
+		exynos_cluster_powerup(cluster);
+		val = S5P_CORE_LOCAL_PWR_EN;
+	} else {
+		exynos_cluster_powerdown(cluster);
+		val = 0;
+	}
+
+	/* Wait until cluster power control is applied */
+	while (tries--) {
+		if (exynos_cluster_power_state(cluster) == val)
+			return 0;
+
+		cpu_relax();
+	}
+	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
+		enable ? "on" : "off");
+
+	return -ETIMEDOUT;
+}
+
+static int exynos_power_up(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+	int err = 0;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+		cluster >= EXYNOS5420_NR_CLUSTERS)
+		return -EINVAL;
+
+	/*
+	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
+	 * variant exists, we need to disable IRQs manually here.
+	 */
+	local_irq_disable();
+	arch_spin_lock(&exynos_mcpm_lock);
+
+	cpu_use_count[cpu][cluster]++;
+	if (cpu_use_count[cpu][cluster] == 1) {
+		bool was_cluster_down =
+			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;
+
+		/*
+		 * Turn on the cluster (L2/COMMON) and then power on the
+		 * cores.
+		 */
+		if (was_cluster_down)
+			err = exynos_cluster_power_control(cluster, 1);
+
+		if (!err)
+			exynos_cpu_powerup(cpunr);
+		else
+			exynos_cluster_power_control(cluster, 0);
+	} else if (cpu_use_count[cpu][cluster] != 2) {
+		/*
+		 * The only possible values are:
+		 * 0 = CPU down
+		 * 1 = CPU (still) up
+		 * 2 = CPU requested to be up before it had a chance
+		 *     to actually make itself down.
+		 * Any other value is a bug.
+		 */
+		BUG();
+	}
+
+	arch_spin_unlock(&exynos_mcpm_lock);
+	local_irq_enable();
+
+	return err;
+}
+
+static void exynos_power_down(void)
+{
+	unsigned int mpidr, cpu, cluster;
+	bool last_man = false, skip_wfi = false;
+	unsigned int cpunr;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	__mcpm_cpu_going_down(cpu, cluster);
+
+	arch_spin_lock(&exynos_mcpm_lock);
+	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
+	cpu_use_count[cpu][cluster]--;
+	if (cpu_use_count[cpu][cluster] == 0) {
+		exynos_cpu_powerdown(cpunr);
+
+		if (exynos_cluster_unused(cluster))
+			last_man = true;
+	} else if (cpu_use_count[cpu][cluster] == 1) {
+		/*
+		 * A power_up request went ahead of us.
+		 * Even if we do not want to shut this CPU down,
+		 * the caller expects a certain state as if the WFI
+		 * was aborted.  So let's continue with cache cleaning.
+		 */
+		skip_wfi = true;
+	} else {
+		BUG();
+	}
+
+	/*
+	 * TODO: Turn off the clusters when all cores in the cluster
+	 * are down to achieve significant power savings.
+	 */
+	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		/* Flush all cache levels for this cluster. */
+		exynos_v7_exit_coherency_flush(all);
+
+		/*
+		 * Disable cluster-level coherency by masking
+		 * incoming snoops and DVM messages:
+		 */
+		cci_disable_port_by_cpu(mpidr);
+
+		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
+	} else {
+		arch_spin_unlock(&exynos_mcpm_lock);
+
+		if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
+			/*
+			 * On the Cortex-A15 we need to disable
+			 * L2 prefetching before flushing the cache.
+			 */
+			asm volatile(
+			"mcr	p15, 1, %0, c15, c0, 3\n\t"
+			"isb\n\t"
+			"dsb"
+			: : "r" (0x400));
+		}
+
+		/* Disable and flush the local CPU cache. */
+		exynos_v7_exit_coherency_flush(louis);
+	}
+
+	__mcpm_cpu_down(cpu, cluster);
+
+	/* Now we are prepared for power-down, do it: */
+	if (!skip_wfi)
+		wfi();
+
+	/* Not dead at this point?  Let our caller cope. */
+}
+
+static int exynos_power_down_finish(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int tries = 100;
+	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	/* Wait for the core state to be OFF */
+	while (tries--) {
+		if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) {
+			if ((exynos_cpu_power_state(cpunr) == 0))
+				return 0; /* success: the CPU is halted */
+		}
+
+		/* Otherwise, wait and retry: */
+		msleep(1);
+	}
+
+	return -ETIMEDOUT; /* timeout */
+}
+
+static const struct mcpm_platform_ops exynos_power_ops = {
+	.power_up		= exynos_power_up,
+	.power_down		= exynos_power_down,
+	.power_down_finish	= exynos_power_down_finish,
+};
+
+static void __init exynos_mcpm_usage_count_init(void)
+{
+	unsigned int mpidr, cpu, cluster;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  ||
+			cluster >= EXYNOS5420_NR_CLUSTERS);
+
+	cpu_use_count[cpu][cluster] = 1;
+}
+
+/*
+ * Enable cluster-level coherency, in preparation for turning on the MMU.
+ */
+static void __naked exynos_pm_power_up_setup(unsigned int affinity_level)
+{
+	asm volatile ("\n"
+	"cmp	r0, #1\n"
+	"bxne	lr\n"
+	"b	cci_enable_port_for_self");
+}
+
+static int __init exynos_mcpm_init(void)
+{
+	struct device_node *node;
+	int ret = 0;
+
+	node = of_find_compatible_node(NULL, NULL, "samsung,exynos5420");
+	if (!node)
+		return -ENODEV;
+	of_node_put(node);
+
+	if (!cci_probed())
+		return -ENODEV;
+
+	node = of_find_compatible_node(NULL, NULL,
+			"samsung,exynos4210-sram-ns");
+	if (!node)
+		return -ENODEV;
+
+	ns_sram_base_addr = of_iomap(node, 0);
+	of_node_put(node);
+	if (!ns_sram_base_addr) {
+		pr_err("failed to map non-secure iRAM base address\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * To increase the stability of KFC reset we need to program
+	 * the PMU SPARE3 register
+	 */
+	__raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3);
+
+	exynos_mcpm_usage_count_init();
+
+	ret = mcpm_platform_register(&exynos_power_ops);
+	if (!ret)
+		ret = mcpm_sync_init(exynos_pm_power_up_setup);
+	if (ret) {
+		iounmap(ns_sram_base_addr);
+		return ret;
+	}
+
+	mcpm_smp_set_ops();
+
+	pr_info("Exynos MCPM support installed\n");
+
+	/*
+	 * Future entries into the kernel can now go
+	 * through the cluster entry vectors.
+	 */
+	__raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 0x1c);
+
+	return ret;
+}
+
+early_initcall(exynos_mcpm_init);
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 6685ebf..f44d318 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -38,6 +38,7 @@
 #define S5P_INFORM5				S5P_PMUREG(0x0814)
 #define S5P_INFORM6				S5P_PMUREG(0x0818)
 #define S5P_INFORM7				S5P_PMUREG(0x081C)
+#define S5P_PMU_SPARE3				S5P_PMUREG(0x090C)
 
 #define S5P_ARM_CORE0_LOWPWR			S5P_PMUREG(0x1000)
 #define S5P_DIS_IRQ_CORE0			S5P_PMUREG(0x1004)
@@ -325,4 +326,6 @@
 
 #define EXYNOS5_OPTION_USE_RETENTION				(1 << 4)
 
+#define EXYNOS5420_SWRESET_KFC_SEL				0x3
+
 #endif /* __ASM_ARCH_REGS_PMU_H */
-- 
1.7.9.5

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

* Re: [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
  2014-05-02 15:25         ` Abhilash Kesavan
@ 2014-05-02 18:16             ` Nicolas Pitre
  -1 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-05-02 18:16 UTC (permalink / raw)
  To: Abhilash Kesavan
  Cc: Dave Martin, Lorenzo Pieralisi,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, t.figa-Sze3O3UU22JBDgjK7y7TUQ,
	abrestic-F7+t8E8rja9g9hUCZPvPmw,
	thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland-5wv7dgnIgG8,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Will Deacon, Arnd Bergmann,
	kesavan.abhilash-Re5JQEeQqe8AvxtiuMwx3w

On Fri, 2 May 2014, Abhilash Kesavan wrote:

> Add machine-dependent MCPM call-backs for Exynos5420. These are used
> to power up/down the secondary CPUs during boot, shutdown, s2r and
> switching.
> 
> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

OK.... There is still a detail wrong.  At least we are converging.

> ---
>  arch/arm/mach-exynos/Kconfig       |    8 +
>  arch/arm/mach-exynos/Makefile      |    2 +
>  arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-exynos/regs-pmu.h    |    3 +
>  4 files changed, 358 insertions(+)
>  create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c
> 
> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
> index 5c34dc2..138070e 100644
> --- a/arch/arm/mach-exynos/Kconfig
> +++ b/arch/arm/mach-exynos/Kconfig
> @@ -73,4 +73,12 @@ config SOC_EXYNOS5440
>  
>  endmenu
>  
> +config EXYNOS5420_MCPM
> +	bool "Exynos5420 Multi-Cluster PM support"
> +	depends on MCPM && SOC_EXYNOS5420
> +	select ARM_CCI
> +	help
> +	  This is needed to provide CPU and cluster power management
> +	  on Exynos5420 implementing big.LITTLE.
> +
>  endif
> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
> index a656dbe..01bc9b9 100644
> --- a/arch/arm/mach-exynos/Makefile
> +++ b/arch/arm/mach-exynos/Makefile
> @@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= firmware.o
>  
>  plus_sec := $(call as-instr,.arch_extension sec,+sec)
>  AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec)
> +
> +obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o
> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
> new file mode 100644
> index 0000000..d0f7461
> --- /dev/null
> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
> @@ -0,0 +1,345 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * arch/arm/mach-exynos/mcpm-exynos.c
> + *
> + * Based on arch/arm/mach-vexpress/dcscb.c
> + *
> + * 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/arm-cci.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +
> +#include <asm/cputype.h>
> +#include <asm/cp15.h>
> +#include <asm/mcpm.h>
> +
> +#include "regs-pmu.h"
> +#include "common.h"
> +
> +#define EXYNOS5420_CPUS_PER_CLUSTER	4
> +#define EXYNOS5420_NR_CLUSTERS		2
> +
> +/* Non-secure iRAM base address */
> +static void __iomem *ns_sram_base_addr;
> +
> +/*
> + * The common v7_exit_coherency_flush API could not be used because of the
> + * Erratum 799270 workaround. This macro is the same as the common one (in
> + * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
> + */
> +#define exynos_v7_exit_coherency_flush(level) \
> +	asm volatile( \
> +	"stmfd	sp!, {fp, ip}\n\t"\
> +	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \
> +	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \
> +	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \
> +	"isb\n\t"\
> +	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \
> +	"clrex\n\t"\
> +	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \
> +	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \
> +	/* Dummy Load of a device register to avoid Erratum 799270 */ \
> +	"ldr	r4, [%0]\n\t" \
> +	"and	r4, r4, #0\n\t" \
> +	"orr	r0, r0, r4\n\t" \
> +	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \
> +	"isb\n\t" \
> +	"dsb\n\t" \
> +	"ldmfd	sp!, {fp, ip}" \
> +	: \
> +	: "Ir" (S5P_INFORM0) \
> +	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
> +	  "r9", "r10", "lr", "memory")
> +
> +/*
> + * We can't use regular spinlocks. In the switcher case, it is possible
> + * for an outbound CPU to call power_down() after its inbound counterpart
> + * is already live using the same logical CPU number which trips lockdep
> + * debugging.
> + */
> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +static int
> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
> +
> +#define exynos_cluster_unused(cluster) \
> +	(!cpu_use_count[0][cluster] && \
> +	 !cpu_use_count[1][cluster] && \
> +	 !cpu_use_count[2][cluster] && \
> +	 !cpu_use_count[3][cluster])
> +
> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
> +{
> +	unsigned int tries = 100;
> +	unsigned int val;
> +
> +	if (enable) {
> +		exynos_cluster_powerup(cluster);
> +		val = S5P_CORE_LOCAL_PWR_EN;
> +	} else {
> +		exynos_cluster_powerdown(cluster);
> +		val = 0;
> +	}
> +
> +	/* Wait until cluster power control is applied */
> +	while (tries--) {
> +		if (exynos_cluster_power_state(cluster) == val)
> +			return 0;
> +
> +		cpu_relax();
> +	}
> +	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
> +		enable ? "on" : "off");
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
> +{
> +	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +	int err = 0;
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +		cluster >= EXYNOS5420_NR_CLUSTERS)
> +		return -EINVAL;
> +
> +	/*
> +	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
> +	 * variant exists, we need to disable IRQs manually here.
> +	 */
> +	local_irq_disable();
> +	arch_spin_lock(&exynos_mcpm_lock);
> +
> +	cpu_use_count[cpu][cluster]++;
> +	if (cpu_use_count[cpu][cluster] == 1) {
> +		bool was_cluster_down =
> +			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;

This is racy.  I probably made this comment already.  The MCPM cluster 
state may change in mcpm-head.S where concurrency protection is achieved 
with a different mechanism.

What you should do instead is to redefine exynos_cluster_unused() into 
exynos_cluster_usecnt() and simply add all counts together.  You could 
even have:

#define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster)

Yet, here you should use:

	bool was_cluster_down = (exynos_cluster_usecnt(cluster) == 1);

> +
> +		/*
> +		 * Turn on the cluster (L2/COMMON) and then power on the
> +		 * cores.
> +		 */
> +		if (was_cluster_down)
> +			err = exynos_cluster_power_control(cluster, 1);
> +
> +		if (!err)
> +			exynos_cpu_powerup(cpunr);
> +		else
> +			exynos_cluster_power_control(cluster, 0);
> +	} else if (cpu_use_count[cpu][cluster] != 2) {
> +		/*
> +		 * The only possible values are:
> +		 * 0 = CPU down
> +		 * 1 = CPU (still) up
> +		 * 2 = CPU requested to be up before it had a chance
> +		 *     to actually make itself down.
> +		 * Any other value is a bug.
> +		 */
> +		BUG();
> +	}
> +
> +	arch_spin_unlock(&exynos_mcpm_lock);
> +	local_irq_enable();
> +
> +	return err;
> +}
> +
> +static void exynos_power_down(void)
> +{
> +	unsigned int mpidr, cpu, cluster;
> +	bool last_man = false, skip_wfi = false;
> +	unsigned int cpunr;
> +
> +	mpidr = read_cpuid_mpidr();
> +	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +			cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +	__mcpm_cpu_going_down(cpu, cluster);
> +
> +	arch_spin_lock(&exynos_mcpm_lock);
> +	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +	cpu_use_count[cpu][cluster]--;
> +	if (cpu_use_count[cpu][cluster] == 0) {
> +		exynos_cpu_powerdown(cpunr);
> +
> +		if (exynos_cluster_unused(cluster))
> +			last_man = true;
> +	} else if (cpu_use_count[cpu][cluster] == 1) {
> +		/*
> +		 * A power_up request went ahead of us.
> +		 * Even if we do not want to shut this CPU down,
> +		 * the caller expects a certain state as if the WFI
> +		 * was aborted.  So let's continue with cache cleaning.
> +		 */
> +		skip_wfi = true;
> +	} else {
> +		BUG();
> +	}
> +
> +	/*
> +	 * TODO: Turn off the clusters when all cores in the cluster
> +	 * are down to achieve significant power savings.
> +	 */

This comment should actually be located right after the 
"if (exynos_cluster_unused(cluster))" above.  That is where the cluster 
control should be applied, assuming it'll be effective only when WFI is 
executed.


> +	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> +		arch_spin_unlock(&exynos_mcpm_lock);
> +
> +		/* Flush all cache levels for this cluster. */
> +		exynos_v7_exit_coherency_flush(all);
> +
> +		/*
> +		 * Disable cluster-level coherency by masking
> +		 * incoming snoops and DVM messages:
> +		 */
> +		cci_disable_port_by_cpu(mpidr);
> +
> +		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> +	} else {
> +		arch_spin_unlock(&exynos_mcpm_lock);
> +
> +		if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
> +			/*
> +			 * On the Cortex-A15 we need to disable
> +			 * L2 prefetching before flushing the cache.
> +			 */
> +			asm volatile(
> +			"mcr	p15, 1, %0, c15, c0, 3\n\t"
> +			"isb\n\t"
> +			"dsb"
> +			: : "r" (0x400));
> +		}

This doesn't belong here.  That is for the last_man only to do, right 
before the "Flush all cache levels for this cluster" comment.

The rest looks fine to me.


Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
@ 2014-05-02 18:16             ` Nicolas Pitre
  0 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-05-02 18:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2 May 2014, Abhilash Kesavan wrote:

> Add machine-dependent MCPM call-backs for Exynos5420. These are used
> to power up/down the secondary CPUs during boot, shutdown, s2r and
> switching.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>

OK.... There is still a detail wrong.  At least we are converging.

> ---
>  arch/arm/mach-exynos/Kconfig       |    8 +
>  arch/arm/mach-exynos/Makefile      |    2 +
>  arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-exynos/regs-pmu.h    |    3 +
>  4 files changed, 358 insertions(+)
>  create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c
> 
> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
> index 5c34dc2..138070e 100644
> --- a/arch/arm/mach-exynos/Kconfig
> +++ b/arch/arm/mach-exynos/Kconfig
> @@ -73,4 +73,12 @@ config SOC_EXYNOS5440
>  
>  endmenu
>  
> +config EXYNOS5420_MCPM
> +	bool "Exynos5420 Multi-Cluster PM support"
> +	depends on MCPM && SOC_EXYNOS5420
> +	select ARM_CCI
> +	help
> +	  This is needed to provide CPU and cluster power management
> +	  on Exynos5420 implementing big.LITTLE.
> +
>  endif
> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
> index a656dbe..01bc9b9 100644
> --- a/arch/arm/mach-exynos/Makefile
> +++ b/arch/arm/mach-exynos/Makefile
> @@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)	+= firmware.o
>  
>  plus_sec := $(call as-instr,.arch_extension sec,+sec)
>  AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec)
> +
> +obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o
> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
> new file mode 100644
> index 0000000..d0f7461
> --- /dev/null
> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
> @@ -0,0 +1,345 @@
> +/*
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * arch/arm/mach-exynos/mcpm-exynos.c
> + *
> + * Based on arch/arm/mach-vexpress/dcscb.c
> + *
> + * 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/arm-cci.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +
> +#include <asm/cputype.h>
> +#include <asm/cp15.h>
> +#include <asm/mcpm.h>
> +
> +#include "regs-pmu.h"
> +#include "common.h"
> +
> +#define EXYNOS5420_CPUS_PER_CLUSTER	4
> +#define EXYNOS5420_NR_CLUSTERS		2
> +
> +/* Non-secure iRAM base address */
> +static void __iomem *ns_sram_base_addr;
> +
> +/*
> + * The common v7_exit_coherency_flush API could not be used because of the
> + * Erratum 799270 workaround. This macro is the same as the common one (in
> + * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
> + */
> +#define exynos_v7_exit_coherency_flush(level) \
> +	asm volatile( \
> +	"stmfd	sp!, {fp, ip}\n\t"\
> +	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \
> +	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \
> +	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \
> +	"isb\n\t"\
> +	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \
> +	"clrex\n\t"\
> +	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \
> +	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \
> +	/* Dummy Load of a device register to avoid Erratum 799270 */ \
> +	"ldr	r4, [%0]\n\t" \
> +	"and	r4, r4, #0\n\t" \
> +	"orr	r0, r0, r4\n\t" \
> +	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \
> +	"isb\n\t" \
> +	"dsb\n\t" \
> +	"ldmfd	sp!, {fp, ip}" \
> +	: \
> +	: "Ir" (S5P_INFORM0) \
> +	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
> +	  "r9", "r10", "lr", "memory")
> +
> +/*
> + * We can't use regular spinlocks. In the switcher case, it is possible
> + * for an outbound CPU to call power_down() after its inbound counterpart
> + * is already live using the same logical CPU number which trips lockdep
> + * debugging.
> + */
> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +static int
> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
> +
> +#define exynos_cluster_unused(cluster) \
> +	(!cpu_use_count[0][cluster] && \
> +	 !cpu_use_count[1][cluster] && \
> +	 !cpu_use_count[2][cluster] && \
> +	 !cpu_use_count[3][cluster])
> +
> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
> +{
> +	unsigned int tries = 100;
> +	unsigned int val;
> +
> +	if (enable) {
> +		exynos_cluster_powerup(cluster);
> +		val = S5P_CORE_LOCAL_PWR_EN;
> +	} else {
> +		exynos_cluster_powerdown(cluster);
> +		val = 0;
> +	}
> +
> +	/* Wait until cluster power control is applied */
> +	while (tries--) {
> +		if (exynos_cluster_power_state(cluster) == val)
> +			return 0;
> +
> +		cpu_relax();
> +	}
> +	pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
> +		enable ? "on" : "off");
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
> +{
> +	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +	int err = 0;
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +		cluster >= EXYNOS5420_NR_CLUSTERS)
> +		return -EINVAL;
> +
> +	/*
> +	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
> +	 * variant exists, we need to disable IRQs manually here.
> +	 */
> +	local_irq_disable();
> +	arch_spin_lock(&exynos_mcpm_lock);
> +
> +	cpu_use_count[cpu][cluster]++;
> +	if (cpu_use_count[cpu][cluster] == 1) {
> +		bool was_cluster_down =
> +			__mcpm_cluster_state(cluster) == CLUSTER_DOWN;

This is racy.  I probably made this comment already.  The MCPM cluster 
state may change in mcpm-head.S where concurrency protection is achieved 
with a different mechanism.

What you should do instead is to redefine exynos_cluster_unused() into 
exynos_cluster_usecnt() and simply add all counts together.  You could 
even have:

#define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster)

Yet, here you should use:

	bool was_cluster_down = (exynos_cluster_usecnt(cluster) == 1);

> +
> +		/*
> +		 * Turn on the cluster (L2/COMMON) and then power on the
> +		 * cores.
> +		 */
> +		if (was_cluster_down)
> +			err = exynos_cluster_power_control(cluster, 1);
> +
> +		if (!err)
> +			exynos_cpu_powerup(cpunr);
> +		else
> +			exynos_cluster_power_control(cluster, 0);
> +	} else if (cpu_use_count[cpu][cluster] != 2) {
> +		/*
> +		 * The only possible values are:
> +		 * 0 = CPU down
> +		 * 1 = CPU (still) up
> +		 * 2 = CPU requested to be up before it had a chance
> +		 *     to actually make itself down.
> +		 * Any other value is a bug.
> +		 */
> +		BUG();
> +	}
> +
> +	arch_spin_unlock(&exynos_mcpm_lock);
> +	local_irq_enable();
> +
> +	return err;
> +}
> +
> +static void exynos_power_down(void)
> +{
> +	unsigned int mpidr, cpu, cluster;
> +	bool last_man = false, skip_wfi = false;
> +	unsigned int cpunr;
> +
> +	mpidr = read_cpuid_mpidr();
> +	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
> +
> +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
> +			cluster >= EXYNOS5420_NR_CLUSTERS);
> +
> +	__mcpm_cpu_going_down(cpu, cluster);
> +
> +	arch_spin_lock(&exynos_mcpm_lock);
> +	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +	cpu_use_count[cpu][cluster]--;
> +	if (cpu_use_count[cpu][cluster] == 0) {
> +		exynos_cpu_powerdown(cpunr);
> +
> +		if (exynos_cluster_unused(cluster))
> +			last_man = true;
> +	} else if (cpu_use_count[cpu][cluster] == 1) {
> +		/*
> +		 * A power_up request went ahead of us.
> +		 * Even if we do not want to shut this CPU down,
> +		 * the caller expects a certain state as if the WFI
> +		 * was aborted.  So let's continue with cache cleaning.
> +		 */
> +		skip_wfi = true;
> +	} else {
> +		BUG();
> +	}
> +
> +	/*
> +	 * TODO: Turn off the clusters when all cores in the cluster
> +	 * are down to achieve significant power savings.
> +	 */

This comment should actually be located right after the 
"if (exynos_cluster_unused(cluster))" above.  That is where the cluster 
control should be applied, assuming it'll be effective only when WFI is 
executed.


> +	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> +		arch_spin_unlock(&exynos_mcpm_lock);
> +
> +		/* Flush all cache levels for this cluster. */
> +		exynos_v7_exit_coherency_flush(all);
> +
> +		/*
> +		 * Disable cluster-level coherency by masking
> +		 * incoming snoops and DVM messages:
> +		 */
> +		cci_disable_port_by_cpu(mpidr);
> +
> +		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> +	} else {
> +		arch_spin_unlock(&exynos_mcpm_lock);
> +
> +		if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
> +			/*
> +			 * On the Cortex-A15 we need to disable
> +			 * L2 prefetching before flushing the cache.
> +			 */
> +			asm volatile(
> +			"mcr	p15, 1, %0, c15, c0, 3\n\t"
> +			"isb\n\t"
> +			"dsb"
> +			: : "r" (0x400));
> +		}

This doesn't belong here.  That is for the last_man only to do, right 
before the "Flush all cache levels for this cluster" comment.

The rest looks fine to me.


Nicolas

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

* Re: [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
  2014-05-02 18:16             ` Nicolas Pitre
@ 2014-05-02 18:23                 ` Andrew Bresticker
  -1 siblings, 0 replies; 60+ messages in thread
From: Andrew Bresticker @ 2014-05-02 18:23 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Abhilash Kesavan, Dave Martin, Lorenzo Pieralisi,
	daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Kukjin Kim,
	Tomasz Figa, thomas.ab-Sze3O3UU22JBDgjK7y7TUQ,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Grant Likely, Rob Herring,
	Will Deacon, Arnd Bergmann, Abhilash Kesavan

>> +     /*
>> +      * TODO: Turn off the clusters when all cores in the cluster
>> +      * are down to achieve significant power savings.
>> +      */
>
> This comment should actually be located right after the
> "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
> control should be applied, assuming it'll be effective only when WFI is
> executed.

Correct me if I'm wrong Samsung folks, but I thought it was not
possible to apply cluster power control from a CPU within the cluster
being powered down, i.e. a CPU in the other cluster must be the one to
apply the cluster power control to power down the outbound cluster.

-Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
@ 2014-05-02 18:23                 ` Andrew Bresticker
  0 siblings, 0 replies; 60+ messages in thread
From: Andrew Bresticker @ 2014-05-02 18:23 UTC (permalink / raw)
  To: linux-arm-kernel

>> +     /*
>> +      * TODO: Turn off the clusters when all cores in the cluster
>> +      * are down to achieve significant power savings.
>> +      */
>
> This comment should actually be located right after the
> "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
> control should be applied, assuming it'll be effective only when WFI is
> executed.

Correct me if I'm wrong Samsung folks, but I thought it was not
possible to apply cluster power control from a CPU within the cluster
being powered down, i.e. a CPU in the other cluster must be the one to
apply the cluster power control to power down the outbound cluster.

-Andrew

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

* Re: [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
  2014-05-02 18:23                 ` Andrew Bresticker
@ 2014-05-02 18:37                   ` Nicolas Pitre
  -1 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-05-02 18:37 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Mark Rutland, devicetree, Abhilash Kesavan, Kukjin Kim,
	Arnd Bergmann, Tomasz Figa, daniel.lezcano, Will Deacon,
	Rob Herring, Grant Likely, Lorenzo Pieralisi, thomas.ab,
	Abhilash Kesavan, Dave Martin, linux-arm-kernel, inderpal.s

On Fri, 2 May 2014, Andrew Bresticker wrote:

> >> +     /*
> >> +      * TODO: Turn off the clusters when all cores in the cluster
> >> +      * are down to achieve significant power savings.
> >> +      */
> >
> > This comment should actually be located right after the
> > "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
> > control should be applied, assuming it'll be effective only when WFI is
> > executed.
> 
> Correct me if I'm wrong Samsung folks, but I thought it was not
> possible to apply cluster power control from a CPU within the cluster
> being powered down, i.e. a CPU in the other cluster must be the one to
> apply the cluster power control to power down the outbound cluster.

Is this true even for deep idle C-states?


Nicolas

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
@ 2014-05-02 18:37                   ` Nicolas Pitre
  0 siblings, 0 replies; 60+ messages in thread
From: Nicolas Pitre @ 2014-05-02 18:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2 May 2014, Andrew Bresticker wrote:

> >> +     /*
> >> +      * TODO: Turn off the clusters when all cores in the cluster
> >> +      * are down to achieve significant power savings.
> >> +      */
> >
> > This comment should actually be located right after the
> > "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
> > control should be applied, assuming it'll be effective only when WFI is
> > executed.
> 
> Correct me if I'm wrong Samsung folks, but I thought it was not
> possible to apply cluster power control from a CPU within the cluster
> being powered down, i.e. a CPU in the other cluster must be the one to
> apply the cluster power control to power down the outbound cluster.

Is this true even for deep idle C-states?


Nicolas

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

* Re: [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
  2014-05-02 18:16             ` Nicolas Pitre
@ 2014-05-05 16:25                 ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-05 16:25 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: Dave Martin, Lorenzo Pieralisi, Daniel Lezcano, linux-arm-kernel,
	Kukjin Kim, Tomasz Figa, Andrew Bresticker, Thomas P Abraham,
	inderpal.s-Sze3O3UU22JBDgjK7y7TUQ, mark.rutland, devicetree,
	Grant Likely, robh+dt, Will Deacon, Arnd Bergmann

Hi Nicolas,

On Fri, May 2, 2014 at 11:46 PM, Nicolas Pitre <nicolas.pitre-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> On Fri, 2 May 2014, Abhilash Kesavan wrote:
>
>> Add machine-dependent MCPM call-backs for Exynos5420. These are used
>> to power up/down the secondary CPUs during boot, shutdown, s2r and
>> switching.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Inderpal Singh <inderpal.s-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>
> OK.... There is still a detail wrong.  At least we are converging.
>
>> ---
>>  arch/arm/mach-exynos/Kconfig       |    8 +
>>  arch/arm/mach-exynos/Makefile      |    2 +
>>  arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
>>  arch/arm/mach-exynos/regs-pmu.h    |    3 +
>>  4 files changed, 358 insertions(+)
>>  create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c
>>
>> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
>> index 5c34dc2..138070e 100644
>> --- a/arch/arm/mach-exynos/Kconfig
>> +++ b/arch/arm/mach-exynos/Kconfig
>> @@ -73,4 +73,12 @@ config SOC_EXYNOS5440
>>
>>  endmenu
>>
>> +config EXYNOS5420_MCPM
>> +     bool "Exynos5420 Multi-Cluster PM support"
>> +     depends on MCPM && SOC_EXYNOS5420
>> +     select ARM_CCI
>> +     help
>> +       This is needed to provide CPU and cluster power management
>> +       on Exynos5420 implementing big.LITTLE.
>> +
>>  endif
>> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
>> index a656dbe..01bc9b9 100644
>> --- a/arch/arm/mach-exynos/Makefile
>> +++ b/arch/arm/mach-exynos/Makefile
>> @@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)   += firmware.o
>>
>>  plus_sec := $(call as-instr,.arch_extension sec,+sec)
>>  AFLAGS_exynos-smc.o          :=-Wa,-march=armv7-a$(plus_sec)
>> +
>> +obj-$(CONFIG_EXYNOS5420_MCPM)        += mcpm-exynos.o
>> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
>> new file mode 100644
>> index 0000000..d0f7461
>> --- /dev/null
>> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
>> @@ -0,0 +1,345 @@
>> +/*
>> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
>> + *           http://www.samsung.com
>> + *
>> + * arch/arm/mach-exynos/mcpm-exynos.c
>> + *
>> + * Based on arch/arm/mach-vexpress/dcscb.c
>> + *
>> + * 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/arm-cci.h>
>> +#include <linux/delay.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.h>
>> +
>> +#include <asm/cputype.h>
>> +#include <asm/cp15.h>
>> +#include <asm/mcpm.h>
>> +
>> +#include "regs-pmu.h"
>> +#include "common.h"
>> +
>> +#define EXYNOS5420_CPUS_PER_CLUSTER  4
>> +#define EXYNOS5420_NR_CLUSTERS               2
>> +
>> +/* Non-secure iRAM base address */
>> +static void __iomem *ns_sram_base_addr;
>> +
>> +/*
>> + * The common v7_exit_coherency_flush API could not be used because of the
>> + * Erratum 799270 workaround. This macro is the same as the common one (in
>> + * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
>> + */
>> +#define exynos_v7_exit_coherency_flush(level) \
>> +     asm volatile( \
>> +     "stmfd  sp!, {fp, ip}\n\t"\
>> +     "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
>> +     "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
>> +     "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
>> +     "isb\n\t"\
>> +     "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
>> +     "clrex\n\t"\
>> +     "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
>> +     "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
>> +     /* Dummy Load of a device register to avoid Erratum 799270 */ \
>> +     "ldr    r4, [%0]\n\t" \
>> +     "and    r4, r4, #0\n\t" \
>> +     "orr    r0, r0, r4\n\t" \
>> +     "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
>> +     "isb\n\t" \
>> +     "dsb\n\t" \
>> +     "ldmfd  sp!, {fp, ip}" \
>> +     : \
>> +     : "Ir" (S5P_INFORM0) \
>> +     : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
>> +       "r9", "r10", "lr", "memory")
>> +
>> +/*
>> + * We can't use regular spinlocks. In the switcher case, it is possible
>> + * for an outbound CPU to call power_down() after its inbound counterpart
>> + * is already live using the same logical CPU number which trips lockdep
>> + * debugging.
>> + */
>> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
>> +static int
>> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
>> +
>> +#define exynos_cluster_unused(cluster) \
>> +     (!cpu_use_count[0][cluster] && \
>> +      !cpu_use_count[1][cluster] && \
>> +      !cpu_use_count[2][cluster] && \
>> +      !cpu_use_count[3][cluster])
>> +
>> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
>> +{
>> +     unsigned int tries = 100;
>> +     unsigned int val;
>> +
>> +     if (enable) {
>> +             exynos_cluster_powerup(cluster);
>> +             val = S5P_CORE_LOCAL_PWR_EN;
>> +     } else {
>> +             exynos_cluster_powerdown(cluster);
>> +             val = 0;
>> +     }
>> +
>> +     /* Wait until cluster power control is applied */
>> +     while (tries--) {
>> +             if (exynos_cluster_power_state(cluster) == val)
>> +                     return 0;
>> +
>> +             cpu_relax();
>> +     }
>> +     pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
>> +             enable ? "on" : "off");
>> +
>> +     return -ETIMEDOUT;
>> +}
>> +
>> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
>> +{
>> +     unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +     int err = 0;
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +             cluster >= EXYNOS5420_NR_CLUSTERS)
>> +             return -EINVAL;
>> +
>> +     /*
>> +      * Since this is called with IRQs enabled, and no arch_spin_lock_irq
>> +      * variant exists, we need to disable IRQs manually here.
>> +      */
>> +     local_irq_disable();
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +
>> +     cpu_use_count[cpu][cluster]++;
>> +     if (cpu_use_count[cpu][cluster] == 1) {
>> +             bool was_cluster_down =
>> +                     __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
>
> This is racy.  I probably made this comment already.  The MCPM cluster
> state may change in mcpm-head.S where concurrency protection is achieved
> with a different mechanism.
>
> What you should do instead is to redefine exynos_cluster_unused() into
> exynos_cluster_usecnt() and simply add all counts together.  You could
> even have:
>
> #define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster)
>
> Yet, here you should use:
>
>         bool was_cluster_down = (exynos_cluster_usecnt(cluster) == 1);
Fixed as per suggestion.
>
>> +
>> +             /*
>> +              * Turn on the cluster (L2/COMMON) and then power on the
>> +              * cores.
>> +              */
>> +             if (was_cluster_down)
>> +                     err = exynos_cluster_power_control(cluster, 1);
>> +
>> +             if (!err)
>> +                     exynos_cpu_powerup(cpunr);
>> +             else
>> +                     exynos_cluster_power_control(cluster, 0);
>> +     } else if (cpu_use_count[cpu][cluster] != 2) {
>> +             /*
>> +              * The only possible values are:
>> +              * 0 = CPU down
>> +              * 1 = CPU (still) up
>> +              * 2 = CPU requested to be up before it had a chance
>> +              *     to actually make itself down.
>> +              * Any other value is a bug.
>> +              */
>> +             BUG();
>> +     }
>> +
>> +     arch_spin_unlock(&exynos_mcpm_lock);
>> +     local_irq_enable();
>> +
>> +     return err;
>> +}
>> +
>> +static void exynos_power_down(void)
>> +{
>> +     unsigned int mpidr, cpu, cluster;
>> +     bool last_man = false, skip_wfi = false;
>> +     unsigned int cpunr;
>> +
>> +     mpidr = read_cpuid_mpidr();
>> +     cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +     cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +     cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                     cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +     __mcpm_cpu_going_down(cpu, cluster);
>> +
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +     BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
>> +     cpu_use_count[cpu][cluster]--;
>> +     if (cpu_use_count[cpu][cluster] == 0) {
>> +             exynos_cpu_powerdown(cpunr);
>> +
>> +             if (exynos_cluster_unused(cluster))
>> +                     last_man = true;
>> +     } else if (cpu_use_count[cpu][cluster] == 1) {
>> +             /*
>> +              * A power_up request went ahead of us.
>> +              * Even if we do not want to shut this CPU down,
>> +              * the caller expects a certain state as if the WFI
>> +              * was aborted.  So let's continue with cache cleaning.
>> +              */
>> +             skip_wfi = true;
>> +     } else {
>> +             BUG();
>> +     }
>> +
>> +     /*
>> +      * TODO: Turn off the clusters when all cores in the cluster
>> +      * are down to achieve significant power savings.
>> +      */
>
> This comment should actually be located right after the
> "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
> control should be applied, assuming it'll be effective only when WFI is
> executed.
OK.
>
>
>> +     if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
>> +             arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +             /* Flush all cache levels for this cluster. */
>> +             exynos_v7_exit_coherency_flush(all);
>> +
>> +             /*
>> +              * Disable cluster-level coherency by masking
>> +              * incoming snoops and DVM messages:
>> +              */
>> +             cci_disable_port_by_cpu(mpidr);
>> +
>> +             __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
>> +     } else {
>> +             arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +             if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
>> +                     /*
>> +                      * On the Cortex-A15 we need to disable
>> +                      * L2 prefetching before flushing the cache.
>> +                      */
>> +                     asm volatile(
>> +                     "mcr    p15, 1, %0, c15, c0, 3\n\t"
>> +                     "isb\n\t"
>> +                     "dsb"
>> +                     : : "r" (0x400));
>> +             }
>
> This doesn't belong here.  That is for the last_man only to do, right
> before the "Flush all cache levels for this cluster" comment.
This was a bad miss on my part. Will fix.
>
> The rest looks fine to me.
Will post v5 soon.

Regards,
Abhilash
>
>
> Nicolas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
@ 2014-05-05 16:25                 ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-05 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Nicolas,

On Fri, May 2, 2014 at 11:46 PM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> On Fri, 2 May 2014, Abhilash Kesavan wrote:
>
>> Add machine-dependent MCPM call-backs for Exynos5420. These are used
>> to power up/down the secondary CPUs during boot, shutdown, s2r and
>> switching.
>>
>> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> Signed-off-by: Inderpal Singh <inderpal.s@samsung.com>
>> Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
>> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
>
> OK.... There is still a detail wrong.  At least we are converging.
>
>> ---
>>  arch/arm/mach-exynos/Kconfig       |    8 +
>>  arch/arm/mach-exynos/Makefile      |    2 +
>>  arch/arm/mach-exynos/mcpm-exynos.c |  345 ++++++++++++++++++++++++++++++++++++
>>  arch/arm/mach-exynos/regs-pmu.h    |    3 +
>>  4 files changed, 358 insertions(+)
>>  create mode 100644 arch/arm/mach-exynos/mcpm-exynos.c
>>
>> diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
>> index 5c34dc2..138070e 100644
>> --- a/arch/arm/mach-exynos/Kconfig
>> +++ b/arch/arm/mach-exynos/Kconfig
>> @@ -73,4 +73,12 @@ config SOC_EXYNOS5440
>>
>>  endmenu
>>
>> +config EXYNOS5420_MCPM
>> +     bool "Exynos5420 Multi-Cluster PM support"
>> +     depends on MCPM && SOC_EXYNOS5420
>> +     select ARM_CCI
>> +     help
>> +       This is needed to provide CPU and cluster power management
>> +       on Exynos5420 implementing big.LITTLE.
>> +
>>  endif
>> diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
>> index a656dbe..01bc9b9 100644
>> --- a/arch/arm/mach-exynos/Makefile
>> +++ b/arch/arm/mach-exynos/Makefile
>> @@ -29,3 +29,5 @@ obj-$(CONFIG_ARCH_EXYNOS)   += firmware.o
>>
>>  plus_sec := $(call as-instr,.arch_extension sec,+sec)
>>  AFLAGS_exynos-smc.o          :=-Wa,-march=armv7-a$(plus_sec)
>> +
>> +obj-$(CONFIG_EXYNOS5420_MCPM)        += mcpm-exynos.o
>> diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
>> new file mode 100644
>> index 0000000..d0f7461
>> --- /dev/null
>> +++ b/arch/arm/mach-exynos/mcpm-exynos.c
>> @@ -0,0 +1,345 @@
>> +/*
>> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
>> + *           http://www.samsung.com
>> + *
>> + * arch/arm/mach-exynos/mcpm-exynos.c
>> + *
>> + * Based on arch/arm/mach-vexpress/dcscb.c
>> + *
>> + * 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/arm-cci.h>
>> +#include <linux/delay.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.h>
>> +
>> +#include <asm/cputype.h>
>> +#include <asm/cp15.h>
>> +#include <asm/mcpm.h>
>> +
>> +#include "regs-pmu.h"
>> +#include "common.h"
>> +
>> +#define EXYNOS5420_CPUS_PER_CLUSTER  4
>> +#define EXYNOS5420_NR_CLUSTERS               2
>> +
>> +/* Non-secure iRAM base address */
>> +static void __iomem *ns_sram_base_addr;
>> +
>> +/*
>> + * The common v7_exit_coherency_flush API could not be used because of the
>> + * Erratum 799270 workaround. This macro is the same as the common one (in
>> + * arch/arm/include/asm/cacheflush.h) except for the erratum handling.
>> + */
>> +#define exynos_v7_exit_coherency_flush(level) \
>> +     asm volatile( \
>> +     "stmfd  sp!, {fp, ip}\n\t"\
>> +     "mrc    p15, 0, r0, c1, c0, 0   @ get SCTLR\n\t" \
>> +     "bic    r0, r0, #"__stringify(CR_C)"\n\t" \
>> +     "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
>> +     "isb\n\t"\
>> +     "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
>> +     "clrex\n\t"\
>> +     "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
>> +     "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
>> +     /* Dummy Load of a device register to avoid Erratum 799270 */ \
>> +     "ldr    r4, [%0]\n\t" \
>> +     "and    r4, r4, #0\n\t" \
>> +     "orr    r0, r0, r4\n\t" \
>> +     "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR\n\t" \
>> +     "isb\n\t" \
>> +     "dsb\n\t" \
>> +     "ldmfd  sp!, {fp, ip}" \
>> +     : \
>> +     : "Ir" (S5P_INFORM0) \
>> +     : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
>> +       "r9", "r10", "lr", "memory")
>> +
>> +/*
>> + * We can't use regular spinlocks. In the switcher case, it is possible
>> + * for an outbound CPU to call power_down() after its inbound counterpart
>> + * is already live using the same logical CPU number which trips lockdep
>> + * debugging.
>> + */
>> +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
>> +static int
>> +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS];
>> +
>> +#define exynos_cluster_unused(cluster) \
>> +     (!cpu_use_count[0][cluster] && \
>> +      !cpu_use_count[1][cluster] && \
>> +      !cpu_use_count[2][cluster] && \
>> +      !cpu_use_count[3][cluster])
>> +
>> +static int exynos_cluster_power_control(unsigned int cluster, int enable)
>> +{
>> +     unsigned int tries = 100;
>> +     unsigned int val;
>> +
>> +     if (enable) {
>> +             exynos_cluster_powerup(cluster);
>> +             val = S5P_CORE_LOCAL_PWR_EN;
>> +     } else {
>> +             exynos_cluster_powerdown(cluster);
>> +             val = 0;
>> +     }
>> +
>> +     /* Wait until cluster power control is applied */
>> +     while (tries--) {
>> +             if (exynos_cluster_power_state(cluster) == val)
>> +                     return 0;
>> +
>> +             cpu_relax();
>> +     }
>> +     pr_warn("timed out waiting for cluster %u to power %s\n", cluster,
>> +             enable ? "on" : "off");
>> +
>> +     return -ETIMEDOUT;
>> +}
>> +
>> +static int exynos_power_up(unsigned int cpu, unsigned int cluster)
>> +{
>> +     unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +     int err = 0;
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +             cluster >= EXYNOS5420_NR_CLUSTERS)
>> +             return -EINVAL;
>> +
>> +     /*
>> +      * Since this is called with IRQs enabled, and no arch_spin_lock_irq
>> +      * variant exists, we need to disable IRQs manually here.
>> +      */
>> +     local_irq_disable();
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +
>> +     cpu_use_count[cpu][cluster]++;
>> +     if (cpu_use_count[cpu][cluster] == 1) {
>> +             bool was_cluster_down =
>> +                     __mcpm_cluster_state(cluster) == CLUSTER_DOWN;
>
> This is racy.  I probably made this comment already.  The MCPM cluster
> state may change in mcpm-head.S where concurrency protection is achieved
> with a different mechanism.
>
> What you should do instead is to redefine exynos_cluster_unused() into
> exynos_cluster_usecnt() and simply add all counts together.  You could
> even have:
>
> #define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster)
>
> Yet, here you should use:
>
>         bool was_cluster_down = (exynos_cluster_usecnt(cluster) == 1);
Fixed as per suggestion.
>
>> +
>> +             /*
>> +              * Turn on the cluster (L2/COMMON) and then power on the
>> +              * cores.
>> +              */
>> +             if (was_cluster_down)
>> +                     err = exynos_cluster_power_control(cluster, 1);
>> +
>> +             if (!err)
>> +                     exynos_cpu_powerup(cpunr);
>> +             else
>> +                     exynos_cluster_power_control(cluster, 0);
>> +     } else if (cpu_use_count[cpu][cluster] != 2) {
>> +             /*
>> +              * The only possible values are:
>> +              * 0 = CPU down
>> +              * 1 = CPU (still) up
>> +              * 2 = CPU requested to be up before it had a chance
>> +              *     to actually make itself down.
>> +              * Any other value is a bug.
>> +              */
>> +             BUG();
>> +     }
>> +
>> +     arch_spin_unlock(&exynos_mcpm_lock);
>> +     local_irq_enable();
>> +
>> +     return err;
>> +}
>> +
>> +static void exynos_power_down(void)
>> +{
>> +     unsigned int mpidr, cpu, cluster;
>> +     bool last_man = false, skip_wfi = false;
>> +     unsigned int cpunr;
>> +
>> +     mpidr = read_cpuid_mpidr();
>> +     cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
>> +     cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
>> +     cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER);
>> +
>> +     pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
>> +     BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER ||
>> +                     cluster >= EXYNOS5420_NR_CLUSTERS);
>> +
>> +     __mcpm_cpu_going_down(cpu, cluster);
>> +
>> +     arch_spin_lock(&exynos_mcpm_lock);
>> +     BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
>> +     cpu_use_count[cpu][cluster]--;
>> +     if (cpu_use_count[cpu][cluster] == 0) {
>> +             exynos_cpu_powerdown(cpunr);
>> +
>> +             if (exynos_cluster_unused(cluster))
>> +                     last_man = true;
>> +     } else if (cpu_use_count[cpu][cluster] == 1) {
>> +             /*
>> +              * A power_up request went ahead of us.
>> +              * Even if we do not want to shut this CPU down,
>> +              * the caller expects a certain state as if the WFI
>> +              * was aborted.  So let's continue with cache cleaning.
>> +              */
>> +             skip_wfi = true;
>> +     } else {
>> +             BUG();
>> +     }
>> +
>> +     /*
>> +      * TODO: Turn off the clusters when all cores in the cluster
>> +      * are down to achieve significant power savings.
>> +      */
>
> This comment should actually be located right after the
> "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
> control should be applied, assuming it'll be effective only when WFI is
> executed.
OK.
>
>
>> +     if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
>> +             arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +             /* Flush all cache levels for this cluster. */
>> +             exynos_v7_exit_coherency_flush(all);
>> +
>> +             /*
>> +              * Disable cluster-level coherency by masking
>> +              * incoming snoops and DVM messages:
>> +              */
>> +             cci_disable_port_by_cpu(mpidr);
>> +
>> +             __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
>> +     } else {
>> +             arch_spin_unlock(&exynos_mcpm_lock);
>> +
>> +             if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) {
>> +                     /*
>> +                      * On the Cortex-A15 we need to disable
>> +                      * L2 prefetching before flushing the cache.
>> +                      */
>> +                     asm volatile(
>> +                     "mcr    p15, 1, %0, c15, c0, 3\n\t"
>> +                     "isb\n\t"
>> +                     "dsb"
>> +                     : : "r" (0x400));
>> +             }
>
> This doesn't belong here.  That is for the last_man only to do, right
> before the "Flush all cache levels for this cluster" comment.
This was a bad miss on my part. Will fix.
>
> The rest looks fine to me.
Will post v5 soon.

Regards,
Abhilash
>
>
> Nicolas

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

* Re: [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
  2014-05-02 18:23                 ` Andrew Bresticker
@ 2014-05-05 16:26                     ` Abhilash Kesavan
  -1 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-05 16:26 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Nicolas Pitre, Dave Martin, Lorenzo Pieralisi, Daniel Lezcano,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Kukjin Kim,
	Tomasz Figa, Thomas P Abraham, inderpal.s-Sze3O3UU22JBDgjK7y7TUQ,
	Mark Rutland, devicetree, Grant Likely, Rob Herring, Will Deacon,
	Arnd Bergmann

Hi Andrew,

On Fri, May 2, 2014 at 11:53 PM, Andrew Bresticker
<abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote:
>>> +     /*
>>> +      * TODO: Turn off the clusters when all cores in the cluster
>>> +      * are down to achieve significant power savings.
>>> +      */
>>
>> This comment should actually be located right after the
>> "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
>> control should be applied, assuming it'll be effective only when WFI is
>> executed.
>
> Correct me if I'm wrong Samsung folks, but I thought it was not
> possible to apply cluster power control from a CPU within the cluster
> being powered down, i.e. a CPU in the other cluster must be the one to
> apply the cluster power control to power down the outbound cluster.
I was under the same impression until quite recently. However, based
on inputs from the hardware team, there are bits available (in the
*COMMON_OPTION register) that ensure "ARM_CORE0~3 are turned off
earlier and then ARM_COMMON_L2 is turned off finally". This allows us
to turn off the cluster from a cpu of the same cluster. We have used
these bits in our cluster power down cpuidle state implementation as
well.


Regards,
Abhilash
>
> -Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v4 5/5] arm: exynos: Add MCPM call-back functions
@ 2014-05-05 16:26                     ` Abhilash Kesavan
  0 siblings, 0 replies; 60+ messages in thread
From: Abhilash Kesavan @ 2014-05-05 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andrew,

On Fri, May 2, 2014 at 11:53 PM, Andrew Bresticker
<abrestic@chromium.org> wrote:
>>> +     /*
>>> +      * TODO: Turn off the clusters when all cores in the cluster
>>> +      * are down to achieve significant power savings.
>>> +      */
>>
>> This comment should actually be located right after the
>> "if (exynos_cluster_unused(cluster))" above.  That is where the cluster
>> control should be applied, assuming it'll be effective only when WFI is
>> executed.
>
> Correct me if I'm wrong Samsung folks, but I thought it was not
> possible to apply cluster power control from a CPU within the cluster
> being powered down, i.e. a CPU in the other cluster must be the one to
> apply the cluster power control to power down the outbound cluster.
I was under the same impression until quite recently. However, based
on inputs from the hardware team, there are bits available (in the
*COMMON_OPTION register) that ensure "ARM_CORE0~3 are turned off
earlier and then ARM_COMMON_L2 is turned off finally". This allows us
to turn off the cluster from a cpu of the same cluster. We have used
these bits in our cluster power down cpuidle state implementation as
well.


Regards,
Abhilash
>
> -Andrew

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

end of thread, other threads:[~2014-05-05 16:26 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-26 16:05 [PATCH v3 0/6] MCPM backend for Exynos5420 Abhilash Kesavan
2014-04-26 16:05 ` Abhilash Kesavan
     [not found] ` <1398528348-21214-1-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-04-26 16:05   ` [PATCH v3 1/6] ARM: EXYNOS: Add generic cpu power control functions for all exynos based SoCs Abhilash Kesavan
2014-04-26 16:05     ` Abhilash Kesavan
2014-04-26 16:05   ` [PATCH v3 2/6] ARM: EXYNOS: use generic exynos cpu power control functions Abhilash Kesavan
2014-04-26 16:05     ` Abhilash Kesavan
     [not found]     ` <1398528348-21214-3-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-05-02 15:25       ` [PATCH v4 2/5] " Abhilash Kesavan
2014-05-02 15:25         ` Abhilash Kesavan
2014-04-26 16:05   ` [PATCH v3 3/6] arm: exynos: Add generic cluster " Abhilash Kesavan
2014-04-26 16:05     ` Abhilash Kesavan
     [not found]     ` <1398528348-21214-4-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-05-02 15:25       ` [PATCH v4 3/5] " Abhilash Kesavan
2014-05-02 15:25         ` Abhilash Kesavan
2014-04-26 16:05   ` [PATCH v3 4/6] ARM: dts: exynos5420: add CCI node Abhilash Kesavan
2014-04-26 16:05     ` Abhilash Kesavan
     [not found]     ` <1398528348-21214-5-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-05-02 15:25       ` [PATCH v4 4/5] " Abhilash Kesavan
2014-05-02 15:25         ` Abhilash Kesavan
2014-04-26 16:05   ` [PATCH v3 5/6] arm: exynos: Add MCPM call-back functions Abhilash Kesavan
2014-04-26 16:05     ` Abhilash Kesavan
2014-04-28 17:44     ` Lorenzo Pieralisi
2014-04-28 17:44       ` Lorenzo Pieralisi
     [not found]       ` <20140428174456.GE31782-7AyDDHkRsp3ZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>
2014-04-29  3:32         ` Abhilash Kesavan
2014-04-29  3:32           ` Abhilash Kesavan
     [not found]           ` <CAM4voa=mhcZO9v7nDdrcz+T8RVN-Av3eERVErCX52k1ftUcKcQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-29 18:49             ` Nicolas Pitre
2014-04-29 18:49               ` Nicolas Pitre
     [not found]               ` <alpine.LFD.2.11.1404291435450.980-fMhRO7WWcppj+hNMo8g0rg@public.gmane.org>
2014-04-30  3:01                 ` Abhilash Kesavan
2014-04-30  3:01                   ` Abhilash Kesavan
     [not found]                   ` <CAM4voa=Po9r5MpxyjQKcYhyES1UjfVaqbP_PnKCbsw5LtEkpZg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-30 10:24                     ` Dave Martin
2014-04-30 10:24                       ` Dave Martin
     [not found]     ` <1398528348-21214-6-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-04-30 14:43       ` Nicolas Pitre
2014-04-30 14:43         ` Nicolas Pitre
     [not found]         ` <alpine.LFD.2.11.1404301021270.980-fMhRO7WWcppj+hNMo8g0rg@public.gmane.org>
2014-05-01  9:39           ` Abhilash Kesavan
2014-05-01  9:39             ` Abhilash Kesavan
2014-04-30 14:59       ` Lorenzo Pieralisi
2014-04-30 14:59         ` Lorenzo Pieralisi
     [not found]         ` <20140430145911.GA32671-7AyDDHkRsp3ZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>
2014-05-01  9:39           ` Abhilash Kesavan
2014-05-01  9:39             ` Abhilash Kesavan
2014-05-02 15:25       ` [PATCH v4 5/5] " Abhilash Kesavan
2014-05-02 15:25         ` Abhilash Kesavan
     [not found]         ` <1399044359-15784-1-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-05-02 18:16           ` Nicolas Pitre
2014-05-02 18:16             ` Nicolas Pitre
     [not found]             ` <alpine.LFD.2.11.1405021347500.980-fMhRO7WWcppj+hNMo8g0rg@public.gmane.org>
2014-05-02 18:23               ` Andrew Bresticker
2014-05-02 18:23                 ` Andrew Bresticker
2014-05-02 18:37                 ` Nicolas Pitre
2014-05-02 18:37                   ` Nicolas Pitre
     [not found]                 ` <CAL1qeaHrP+i4EhOQKkSX7xFNyiyBiBfpsV3B0EHCFcrNzc6KLQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-05-05 16:26                   ` Abhilash Kesavan
2014-05-05 16:26                     ` Abhilash Kesavan
2014-05-05 16:25               ` Abhilash Kesavan
2014-05-05 16:25                 ` Abhilash Kesavan
2014-04-26 16:05   ` [PATCH v3 6/6] arm: exynos: Add /dev/bL_status user interface on Exynos5420 Abhilash Kesavan
2014-04-26 16:05     ` Abhilash Kesavan
     [not found]     ` <1398528348-21214-7-git-send-email-a.kesavan-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-04-28 11:25       ` Daniel Lezcano
2014-04-28 11:25         ` Daniel Lezcano
     [not found]         ` <535E3A8C.6070304-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-04-28 12:49           ` Abhilash Kesavan
2014-04-28 12:49             ` Abhilash Kesavan
     [not found]             ` <CAM4voak-oXToBK=owO=jmpwk3rDkg71JS=8YOTz1HfiQvZa5Vw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-30 14:49               ` Nicolas Pitre
2014-04-30 14:49                 ` Nicolas Pitre
     [not found]                 ` <alpine.LFD.2.11.1404301044280.980-fMhRO7WWcppj+hNMo8g0rg@public.gmane.org>
2014-05-01  9:39                   ` Abhilash Kesavan
2014-05-01  9:39                     ` Abhilash Kesavan
2014-05-02 15:24   ` [PATCH v4 0/5] MCPM backend for Exynos5420 Abhilash Kesavan
2014-05-02 15:24     ` Abhilash Kesavan

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.