linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature
@ 2016-08-02 11:59 Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 0/5] powerpc/pm: QorIQ deep sleep Chenhui Zhao
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Chenhui Zhao @ 2016-08-02 11:59 UTC (permalink / raw)
  To: oss, linuxppc-dev, linux-kernel; +Cc: jason.jin, z.chenhui, Chenhui Zhao

Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
 Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 +++++++++++++
 arch/powerpc/boot/dts/fsl/t1040si-post.dtsi        |  3 +++
 2 files changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
index e284e4e..1d44a80 100644
--- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
@@ -21,6 +21,10 @@ Required properites:
 	* "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm
 	* "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm
 
+Optional properites:
+  - mcke-gpios : The GPIO pin is used for keeping the MCKE signal of DDR modules
+		 low in the LPM35 state on some platforms, such as T1040.
+
 All references to "1.0" and "2.0" refer to the QorIQ chassis version to
 which the chip complies.
 Chassis Version		Example Chips
@@ -37,6 +41,15 @@ The RCPM node for T4240:
 		fsl,#rcpm-wakeup-cells = <2>;
 	};
 
+The RCPM node for T1040 (which supports LPM35 state):
+	rcpm: global-utilities@e2000 {
+		compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1";
+		reg = <0xe2000 0x1000>;
+		fsl,#rcpm-wakeup-cells = <1>;
+		mcke-gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>
+	};
+
+
 * Freescale RCPM Wakeup Source Device Tree Bindings
 -------------------------------------------
 Required fsl,rcpm-wakeup property should be added to a device node if the device
diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
index 507649e..f66e7dd 100644
--- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
@@ -33,6 +33,7 @@
  */
 
 #include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/gpio/gpio.h>
 
 &bman_fbpr {
 	compatible = "fsl,bman-fbpr";
@@ -474,6 +475,8 @@
 	rcpm: global-utilities@e2000 {
 		compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1";
 		reg = <0xe2000 0x1000>;
+		fsl,#rcpm-wakeup-cells = <1>;
+		mcke-gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
 	};
 
 	sfp: sfp@e8000 {
-- 
1.9.1

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

* [PATCH v3 0/5] powerpc/pm: QorIQ deep sleep
  2016-08-02 11:59 [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature Chenhui Zhao
@ 2016-08-02 11:59 ` Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 2/5] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM Chenhui Zhao
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Chenhui Zhao @ 2016-08-02 11:59 UTC (permalink / raw)
  To: oss, linuxppc-dev, linux-kernel; +Cc: jason.jin, z.chenhui, Chenhui Zhao

Changes for v3:
* add mcke-gpios in dts to specify the GPIO pin which works as MCKE signal

Changes for v2:
* Ioremap every dts node used in the patches.
* Check the board compatible string to see if the board supports deep sleep.
* Can not reserve the first page of DDR memory, because PPC64 doesn't support
  changing the kernel base address. So still save and restore the first 128 bytes
  of DDR memory.
* Still save and restoer CCSR registers in kernel, because bootloader doesn't
  know what register values to restore
* Changed copyright and email address from freescale to NXP

Please refer to the version 1:
[1/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
http://patchwork.ozlabs.org/patch/502549/

[2/4] powerpc: get the physical base address of DCSR
http://patchwork.ozlabs.org/patch/502551/
It is removed.

[3/4] powerpc: pm: add EPU FSM configuration for deep sleep
http://patchwork.ozlabs.org/patch/502548/

[4/4] powerpc: pm: support deep sleep feature on T104x
http://patchwork.ozlabs.org/patch/502550/


Chenhui Zhao (5):
  powerpc/dts: add mcke-gpios for PM feature
  powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
  powerpc: pm: add EPU FSM configuration for deep sleep
  powerpc/pm: support deep sleep feature on T104x
  powerpc/pm: save and restore registers during deep sleep

 Documentation/devicetree/bindings/soc/fsl/rcpm.txt |  13 +
 arch/powerpc/Kconfig                               |   3 +-
 arch/powerpc/boot/dts/fsl/t1040si-post.dtsi        |   3 +
 arch/powerpc/include/asm/fsl_pm.h                  |  28 +-
 arch/powerpc/kernel/asm-offsets.c                  |  12 +
 arch/powerpc/kernel/fsl_booke_entry_mapping.S      |  10 +
 arch/powerpc/kernel/head_64.S                      |   2 +-
 arch/powerpc/platforms/85xx/Kconfig                |   5 +
 arch/powerpc/platforms/85xx/Makefile               |   2 +
 arch/powerpc/platforms/85xx/deepsleep.c            | 384 +++++++++++++++
 arch/powerpc/platforms/85xx/qoriq_pm.c             |  84 ++++
 arch/powerpc/platforms/85xx/sleep_fsm.c            | 267 +++++++++++
 arch/powerpc/platforms/85xx/sleep_fsm.h            |  92 ++++
 arch/powerpc/platforms/85xx/t104x_deepsleep.S      | 531 +++++++++++++++++++++
 arch/powerpc/platforms/86xx/Kconfig                |   1 +
 arch/powerpc/sysdev/fsl_rcpm.c                     |  28 +-
 16 files changed, 1446 insertions(+), 19 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
 create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c
 create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c
 create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h
 create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S

-- 
1.9.1

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

* [PATCH v3 2/5] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
  2016-08-02 11:59 [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 0/5] powerpc/pm: QorIQ deep sleep Chenhui Zhao
@ 2016-08-02 11:59 ` Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 3/5] powerpc: pm: add EPU FSM configuration for deep sleep Chenhui Zhao
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Chenhui Zhao @ 2016-08-02 11:59 UTC (permalink / raw)
  To: oss, linuxppc-dev, linux-kernel; +Cc: jason.jin, z.chenhui, Chenhui Zhao

In sleep mode, the clocks of e500 cores and unused IP blocks is
turned off. The IP blocks which are allowed to wake up the processor
are still running.

The sleep mode is equal to the Standby state in Linux. Use the
command to enter sleep mode:
  echo standby > /sys/power/state

Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
 arch/powerpc/Kconfig                   |  3 +-
 arch/powerpc/include/asm/fsl_pm.h      |  2 +-
 arch/powerpc/platforms/85xx/Kconfig    |  5 +++
 arch/powerpc/platforms/85xx/Makefile   |  1 +
 arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/86xx/Kconfig    |  1 +
 arch/powerpc/sysdev/fsl_rcpm.c         | 20 ++++--------
 7 files changed, 74 insertions(+), 17 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 0a9d439..078d08c 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -242,7 +242,7 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
 	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-		   (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+		   FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \
 		   || 44x || 40x
 
 config PPC_DCR_NATIVE
@@ -778,7 +778,6 @@ config FSL_PCI
 
 config FSL_PMC
 	bool
-	default y
 	depends on SUSPEND && (PPC_85xx || PPC_86xx)
 	help
 	  Freescale MPC85xx/MPC86xx power management controller support
diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
index 47df55e..e05049b 100644
--- a/arch/powerpc/include/asm/fsl_pm.h
+++ b/arch/powerpc/include/asm/fsl_pm.h
@@ -34,7 +34,7 @@ struct fsl_pm_ops {
 	void (*cpu_exit_state)(int cpu, int state);
 	void (*cpu_up_prepare)(int cpu);
 	void (*cpu_die)(int cpu);
-	int (*plat_enter_sleep)(void);
+	int (*plat_enter_sleep)(int state);
 	void (*freeze_time_base)(bool freeze);
 
 	/* keep the power of IP blocks during sleep/deep sleep */
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index e626461..dff2ea6 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE
 	select SERIAL_8250_EXTENDED if SERIAL_8250
 	select SERIAL_8250_SHARE_IRQ if SERIAL_8250
 	select FSL_CORENET_RCPM if PPC_E500MC
+	select FSL_QORIQ_PM if SUSPEND && PPC_E500MC
+	select FSL_PMC if SUSPEND && !PPC_E500MC
 	default y
 
 if FSL_SOC_BOOKE
@@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE
 
 config TQM85xx
 	bool
+
+config FSL_QORIQ_PM
+	bool
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 7bc86da..fdae28b 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,6 +3,7 @@
 #
 obj-$(CONFIG_SMP) += smp.o
 obj-$(CONFIG_FSL_PMC)		  += mpc85xx_pm_ops.o
+obj-$(CONFIG_FSL_QORIQ_PM)	  += qoriq_pm.o
 
 obj-y += common.o
 
diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
new file mode 100644
index 0000000..c97ef8f
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -0,0 +1,59 @@
+/*
+ * Support Power Management feature
+ *
+ * Copyright 2016 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@nxp.com>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
+
+#include <asm/fsl_pm.h>
+
+static unsigned int pm_modes;
+
+static int qoriq_suspend_enter(suspend_state_t state)
+{
+	int ret = 0;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		ret = qoriq_pm_ops->plat_enter_sleep(FSL_PM_SLEEP);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int qoriq_suspend_valid(suspend_state_t state)
+{
+
+	if (state == PM_SUSPEND_STANDBY && (pm_modes & FSL_PM_SLEEP))
+		return 1;
+
+	return 0;
+}
+
+static const struct platform_suspend_ops qoriq_suspend_ops = {
+	.valid = qoriq_suspend_valid,
+	.enter = qoriq_suspend_enter,
+};
+
+static int __init qoriq_suspend_init(void)
+{
+	/* support sleep by default */
+	pm_modes |= FSL_PM_SLEEP;
+
+	suspend_set_ops(&qoriq_suspend_ops);
+	return 0;
+}
+arch_initcall(qoriq_suspend_init);
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 1afd1e4..09638e0 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -5,6 +5,7 @@ menuconfig PPC_86xx
 	select FSL_SOC
 	select ALTIVEC
 	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select FSL_PMC if SUSPEND
 	help
 	  The Freescale E600 SoCs have 74xx cores.
 
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
index 9259a94..e5447ac 100644
--- a/arch/powerpc/sysdev/fsl_rcpm.c
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -218,14 +218,15 @@ static void rcpm_v2_cpu_up_prepare(int cpu)
 	rcpm_v2_irq_unmask(cpu);
 }
 
-static int rcpm_v1_plat_enter_state(int state)
+static int rcpm_v1_plat_enter_sleep(int state)
 {
 	u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
 	int ret = 0;
 	int result;
 
 	switch (state) {
-	case PLAT_PM_SLEEP:
+	case FSL_PM_SLEEP:
+		cur_cpu_spec->cpu_down_flush();
 		setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
 
 		/* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
@@ -244,14 +245,15 @@ static int rcpm_v1_plat_enter_state(int state)
 	return ret;
 }
 
-static int rcpm_v2_plat_enter_state(int state)
+static int rcpm_v2_plat_enter_sleep(int state)
 {
 	u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr;
 	int ret = 0;
 	int result;
 
 	switch (state) {
-	case PLAT_PM_LPM20:
+	case FSL_PM_SLEEP:
+		cur_cpu_spec->cpu_down_flush();
 		/* clear previous LPM20 status */
 		setbits32(pmcsr_reg, RCPM_POWMGTCSR_P_LPM20_ST);
 		/* enter LPM20 status */
@@ -275,16 +277,6 @@ static int rcpm_v2_plat_enter_state(int state)
 	return ret;
 }
 
-static int rcpm_v1_plat_enter_sleep(void)
-{
-	return rcpm_v1_plat_enter_state(PLAT_PM_SLEEP);
-}
-
-static int rcpm_v2_plat_enter_sleep(void)
-{
-	return rcpm_v2_plat_enter_state(PLAT_PM_LPM20);
-}
-
 static void rcpm_common_freeze_time_base(u32 *tben_reg, int freeze)
 {
 	static u32 mask;
-- 
1.9.1

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

* [PATCH v3 3/5] powerpc: pm: add EPU FSM configuration for deep sleep
  2016-08-02 11:59 [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 0/5] powerpc/pm: QorIQ deep sleep Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 2/5] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM Chenhui Zhao
@ 2016-08-02 11:59 ` Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 4/5] powerpc/pm: support deep sleep feature on T104x Chenhui Zhao
  2016-08-02 11:59 ` [PATCH v3 5/5] powerpc/pm: save and restore registers during deep sleep Chenhui Zhao
  4 siblings, 0 replies; 11+ messages in thread
From: Chenhui Zhao @ 2016-08-02 11:59 UTC (permalink / raw)
  To: oss, linuxppc-dev, linux-kernel; +Cc: jason.jin, z.chenhui, Chenhui Zhao

In the last stage of deep sleep, software will trigger a Finite
State Machine (FSM) to control the hardware precedure, such as
board isolation, killing PLLs, removing power, and so on.

When the system is waked up by an interrupt, the FSM controls the
hardware to complete the early resume precedure.

This patch configure the EPU FSM preparing for deep sleep.

Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
 arch/powerpc/platforms/85xx/Makefile    |   2 +-
 arch/powerpc/platforms/85xx/sleep_fsm.c | 267 ++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/85xx/sleep_fsm.h |  92 +++++++++++
 3 files changed, 360 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c
 create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index fdae28b..87fb847 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_SMP) += smp.o
 obj-$(CONFIG_FSL_PMC)		  += mpc85xx_pm_ops.o
-obj-$(CONFIG_FSL_QORIQ_PM)	  += qoriq_pm.o
+obj-$(CONFIG_FSL_QORIQ_PM)	  += qoriq_pm.o sleep_fsm.o
 
 obj-y += common.o
 
diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.c b/arch/powerpc/platforms/85xx/sleep_fsm.c
new file mode 100644
index 0000000..2b0c16b
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep_fsm.c
@@ -0,0 +1,267 @@
+/*
+ * Freescale deep sleep FSM (finite-state machine) configuration
+ *
+ * Copyright 2016 Freescale Semiconductor Inc.
+ *
+ * Author: Hongbo Zhang <hongbo.zhang@nxp.com>
+ *         Chenhui Zhao <chenhui.zhao@nxp.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include "sleep_fsm.h"
+
+struct fsm_reg_vals {
+	u32 offset;
+	u32 value;
+};
+
+/*
+ * These values are from chip's reference manual. For example,
+ * the values for T1040 can be found in "8.4.3.8 Programming
+ * supporting deep sleep mode" of Chapter 8 "Run Control and
+ * Power Management (RCPM)".
+ * The default value is applied to T1040, T1042, T1024.
+ */
+struct fsm_reg_vals epu_default_val[] = {
+	/* EPGCR (Event Processor Global Control Register) */
+	{EPGCR, 0},
+	/* EPECR (Event Processor Event Control Registers) */
+	{EPECR0 + EPECR_STRIDE * 0, 0},
+	{EPECR0 + EPECR_STRIDE * 1, 0},
+	{EPECR0 + EPECR_STRIDE * 2, 0xF0004004},
+	{EPECR0 + EPECR_STRIDE * 3, 0x80000084},
+	{EPECR0 + EPECR_STRIDE * 4, 0x20000084},
+	{EPECR0 + EPECR_STRIDE * 5, 0x08000004},
+	{EPECR0 + EPECR_STRIDE * 6, 0x80000084},
+	{EPECR0 + EPECR_STRIDE * 7, 0x80000084},
+	{EPECR0 + EPECR_STRIDE * 8, 0x60000084},
+	{EPECR0 + EPECR_STRIDE * 9, 0x08000084},
+	{EPECR0 + EPECR_STRIDE * 10, 0x42000084},
+	{EPECR0 + EPECR_STRIDE * 11, 0x90000084},
+	{EPECR0 + EPECR_STRIDE * 12, 0x80000084},
+	{EPECR0 + EPECR_STRIDE * 13, 0x08000084},
+	{EPECR0 + EPECR_STRIDE * 14, 0x02000084},
+	{EPECR0 + EPECR_STRIDE * 15, 0x00000004},
+	/*
+	 * EPEVTCR (Event Processor EVT Pin Control Registers)
+	 * SCU8 triger EVT2, and SCU11 triger EVT9
+	 */
+	{EPEVTCR0 + EPEVTCR_STRIDE * 0, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 1, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x80000001},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 3, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 4, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 5, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 6, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 7, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 8, 0},
+	{EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB0000001},
+	/* EPCMPR (Event Processor Counter Compare Registers) */
+	{EPCMPR0 + EPCMPR_STRIDE * 0, 0},
+	{EPCMPR0 + EPCMPR_STRIDE * 1, 0},
+	{EPCMPR0 + EPCMPR_STRIDE * 2, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 3, 0},
+	{EPCMPR0 + EPCMPR_STRIDE * 4, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 5, 0x00000020},
+	{EPCMPR0 + EPCMPR_STRIDE * 6, 0},
+	{EPCMPR0 + EPCMPR_STRIDE * 7, 0},
+	{EPCMPR0 + EPCMPR_STRIDE * 8, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 9, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 10, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 11, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 12, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 13, 0},
+	{EPCMPR0 + EPCMPR_STRIDE * 14, 0x000000FF},
+	{EPCMPR0 + EPCMPR_STRIDE * 15, 0x000000FF},
+	/* EPCCR (Event Processor Counter Control Registers) */
+	{EPCCR0 + EPCCR_STRIDE * 0, 0},
+	{EPCCR0 + EPCCR_STRIDE * 1, 0},
+	{EPCCR0 + EPCCR_STRIDE * 2, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 3, 0},
+	{EPCCR0 + EPCCR_STRIDE * 4, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 5, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 6, 0},
+	{EPCCR0 + EPCCR_STRIDE * 7, 0},
+	{EPCCR0 + EPCCR_STRIDE * 8, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 9, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 10, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 11, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 12, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 13, 0},
+	{EPCCR0 + EPCCR_STRIDE * 14, 0x92840000},
+	{EPCCR0 + EPCCR_STRIDE * 15, 0x92840000},
+	/* EPSMCR (Event Processor SCU Mux Control Registers) */
+	{EPSMCR0 + EPSMCR_STRIDE * 0, 0},
+	{EPSMCR0 + EPSMCR_STRIDE * 1, 0},
+	{EPSMCR0 + EPSMCR_STRIDE * 2, 0x6C700000},
+	{EPSMCR0 + EPSMCR_STRIDE * 3, 0x2F000000},
+	{EPSMCR0 + EPSMCR_STRIDE * 4, 0x002F0000},
+	{EPSMCR0 + EPSMCR_STRIDE * 5, 0x00002E00},
+	{EPSMCR0 + EPSMCR_STRIDE * 6, 0x7C000000},
+	{EPSMCR0 + EPSMCR_STRIDE * 7, 0x30000000},
+	{EPSMCR0 + EPSMCR_STRIDE * 8, 0x64300000},
+	{EPSMCR0 + EPSMCR_STRIDE * 9, 0x00003000},
+	{EPSMCR0 + EPSMCR_STRIDE * 10, 0x65000030},
+	{EPSMCR0 + EPSMCR_STRIDE * 11, 0x31740000},
+	{EPSMCR0 + EPSMCR_STRIDE * 12, 0x7F000000},
+	{EPSMCR0 + EPSMCR_STRIDE * 13, 0x00003100},
+	{EPSMCR0 + EPSMCR_STRIDE * 14, 0x00000031},
+	{EPSMCR0 + EPSMCR_STRIDE * 15, 0x76000000},
+	/* EPACR (Event Processor Action Control Registers) */
+	{EPACR0 + EPACR_STRIDE * 0, 0},
+	{EPACR0 + EPACR_STRIDE * 1, 0},
+	{EPACR0 + EPACR_STRIDE * 2, 0},
+	{EPACR0 + EPACR_STRIDE * 3, 0x00000080},
+	{EPACR0 + EPACR_STRIDE * 4, 0},
+	{EPACR0 + EPACR_STRIDE * 5, 0x00000040},
+	{EPACR0 + EPACR_STRIDE * 6, 0},
+	{EPACR0 + EPACR_STRIDE * 7, 0},
+	{EPACR0 + EPACR_STRIDE * 8, 0},
+	{EPACR0 + EPACR_STRIDE * 9, 0x0000001C},
+	{EPACR0 + EPACR_STRIDE * 10, 0x00000020},
+	{EPACR0 + EPACR_STRIDE * 11, 0},
+	{EPACR0 + EPACR_STRIDE * 12, 0x00000003},
+	{EPACR0 + EPACR_STRIDE * 13, 0x06000000},
+	{EPACR0 + EPACR_STRIDE * 14, 0x04000000},
+	{EPACR0 + EPACR_STRIDE * 15, 0x02000000},
+	/* EPIMCR (Event Processor Input Mux Control Registers) */
+	{EPIMCR0 + EPIMCR_STRIDE * 0, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 1, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 2, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 3, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 4, 0x44000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 5, 0x40000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 6, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 7, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 8, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 9, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 10, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 11, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 12, 0x44000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 13, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 14, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 15, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 16, 0x6A000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 17, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 18, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 19, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 20, 0x48000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 21, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 22, 0x6C000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 23, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 24, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 25, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 26, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 27, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 28, 0x76000000},
+	{EPIMCR0 + EPIMCR_STRIDE * 29, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 30, 0},
+	{EPIMCR0 + EPIMCR_STRIDE * 31, 0x76000000},
+	/* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
+	{EPXTRIGCR, 0x0000FFDF},
+	/* end */
+	{FSM_END_FLAG, 0},
+};
+
+struct fsm_reg_vals npc_default_val[] = {
+	/* NPC triggered Memory-Mapped Access Registers */
+	{NCR, 0x80000000},
+	{MCCR1, 0},
+	{MCSR1, 0},
+	{MMAR1LO, 0},
+	{MMAR1HI, 0},
+	{MMDR1, 0},
+	{MCSR2, 0},
+	{MMAR2LO, 0},
+	{MMAR2HI, 0},
+	{MMDR2, 0},
+	{MCSR3, 0x80000000},
+	{MMAR3LO, 0x000E2130},
+	{MMAR3HI, 0x00030000},
+	{MMDR3, 0x00020000},
+	/* end */
+	{FSM_END_FLAG, 0},
+};
+
+/**
+ * fsl_fsm_setup - Configure EPU's FSM registers
+ * @base: the base address of registers
+ * @val: Pointer to address-value pairs for FSM registers
+ */
+static void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val)
+{
+	struct fsm_reg_vals *data = val;
+
+	while (data->offset != FSM_END_FLAG) {
+		iowrite32be(data->value, base + data->offset);
+		data++;
+	}
+}
+
+void fsl_epu_setup_default(void __iomem *epu_base)
+{
+	fsl_fsm_setup(epu_base, epu_default_val);
+}
+
+void fsl_npc_setup_default(void __iomem *npc_base)
+{
+	fsl_fsm_setup(npc_base, npc_default_val);
+}
+
+void fsl_dcsr_rcpm_setup(void __iomem *rcpm_base)
+{
+	iowrite32be(0x00001001, rcpm_base + CSTTACR0);
+	iowrite32be(0x00000001, rcpm_base + CG1CR0);
+}
+
+void fsl_epu_clean_default(void __iomem *epu_base)
+{
+	u32 offset;
+
+	/* follow the exact sequence to clear the registers */
+	/* Clear EPACRn */
+	for (offset = EPACR0; offset <= EPACR15; offset += EPACR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPEVTCRn */
+	for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += EPEVTCR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPGCR */
+	iowrite32be(0, epu_base + EPGCR);
+
+	/* Clear EPSMCRn */
+	for (offset = EPSMCR0; offset <= EPSMCR15; offset += EPSMCR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPCCRn */
+	for (offset = EPCCR0; offset <= EPCCR31; offset += EPCCR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPCMPRn */
+	for (offset = EPCMPR0; offset <= EPCMPR31; offset += EPCMPR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPCTRn */
+	for (offset = EPCTR0; offset <= EPCTR31; offset += EPCTR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPIMCRn */
+	for (offset = EPIMCR0; offset <= EPIMCR31; offset += EPIMCR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+
+	/* Clear EPXTRIGCRn */
+	iowrite32be(0, epu_base + EPXTRIGCR);
+
+	/* Clear EPECRn */
+	for (offset = EPECR0; offset <= EPECR15; offset += EPECR_STRIDE)
+		iowrite32be(0, epu_base + offset);
+}
diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.h b/arch/powerpc/platforms/85xx/sleep_fsm.h
new file mode 100644
index 0000000..a6baa5e
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep_fsm.h
@@ -0,0 +1,92 @@
+/*
+ * Freescale deep sleep FSM (finite-state machine) configuration
+ *
+ * Copyright 2016 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _FSL_SLEEP_FSM_H
+#define _FSL_SLEEP_FSM_H
+
+/* End flag */
+#define FSM_END_FLAG		0xFFFFFFFFUL
+
+/* EPGCR (Event Processor Global Control Register) */
+#define EPGCR		0x000
+
+/* EPEVTCR0-9 (Event Processor EVT Pin Control Registers) */
+#define EPEVTCR0	0x050
+#define EPEVTCR9	0x074
+#define EPEVTCR_STRIDE	4
+
+/* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
+#define EPXTRIGCR	0x090
+
+/* EPIMCR0-31 (Event Processor Input Mux Control Registers) */
+#define EPIMCR0		0x100
+#define EPIMCR31	0x17C
+#define EPIMCR_STRIDE	4
+
+/* EPSMCR0-15 (Event Processor SCU Mux Control Registers) */
+#define EPSMCR0		0x200
+#define EPSMCR15	0x278
+#define EPSMCR_STRIDE	8
+
+/* EPECR0-15 (Event Processor Event Control Registers) */
+#define EPECR0		0x300
+#define EPECR15		0x33C
+#define EPECR_STRIDE	4
+
+/* EPACR0-15 (Event Processor Action Control Registers) */
+#define EPACR0		0x400
+#define EPACR15		0x43C
+#define EPACR_STRIDE	4
+
+/* EPCCRi0-15 (Event Processor Counter Control Registers) */
+#define EPCCR0		0x800
+#define EPCCR15		0x83C
+#define EPCCR31		0x87C
+#define EPCCR_STRIDE	4
+
+/* EPCMPR0-15 (Event Processor Counter Compare Registers) */
+#define EPCMPR0		0x900
+#define EPCMPR15	0x93C
+#define EPCMPR31	0x97C
+#define EPCMPR_STRIDE	4
+
+/* EPCTR0-31 (Event Processor Counter Register) */
+#define EPCTR0		0xA00
+#define EPCTR31		0xA7C
+#define EPCTR_STRIDE	4
+
+/* NPC triggered Memory-Mapped Access Registers */
+#define NCR		0x000
+#define MCCR1		0x0CC
+#define MCSR1		0x0D0
+#define MMAR1LO		0x0D4
+#define MMAR1HI		0x0D8
+#define MMDR1		0x0DC
+#define MCSR2		0x0E0
+#define MMAR2LO		0x0E4
+#define MMAR2HI		0x0E8
+#define MMDR2		0x0EC
+#define MCSR3		0x0F0
+#define MMAR3LO		0x0F4
+#define MMAR3HI		0x0F8
+#define MMDR3		0x0FC
+
+/* RCPM Core State Action Control Register 0 */
+#define CSTTACR0	0xB00
+
+/* RCPM Core Group 1 Configuration Register 0 */
+#define CG1CR0		0x31C
+
+void fsl_epu_setup_default(void __iomem *epu_base);
+void fsl_npc_setup_default(void __iomem *npc_base);
+void fsl_dcsr_rcpm_setup(void __iomem *rcpm_base);
+void fsl_epu_clean_default(void __iomem *epu_base);
+
+#endif /* _FSL_SLEEP_FSM_H */
-- 
1.9.1

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

* [PATCH v3 4/5] powerpc/pm: support deep sleep feature on T104x
  2016-08-02 11:59 [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature Chenhui Zhao
                   ` (2 preceding siblings ...)
  2016-08-02 11:59 ` [PATCH v3 3/5] powerpc: pm: add EPU FSM configuration for deep sleep Chenhui Zhao
@ 2016-08-02 11:59 ` Chenhui Zhao
  2016-09-25  7:24   ` [v3,4/5] " Scott Wood
  2016-08-02 11:59 ` [PATCH v3 5/5] powerpc/pm: save and restore registers during deep sleep Chenhui Zhao
  4 siblings, 1 reply; 11+ messages in thread
From: Chenhui Zhao @ 2016-08-02 11:59 UTC (permalink / raw)
  To: oss, linuxppc-dev, linux-kernel; +Cc: jason.jin, z.chenhui, Chenhui Zhao

T104x has deep sleep feature, which can switch off most parts of
the SoC when it is in deep sleep mode. This way, it becomes more
energy-efficient.

The DDR controller will also be powered off in deep sleep. Therefore,
the last stage (the latter part of fsl_dp_enter_low) will run without DDR
access. This piece of code and related TLBs are prefetched in advance.

Due to the different initialization code between 32-bit and 64-bit, they
have separate resume entry and precedure.

The feature supports 32-bit and 64-bit kernel mode.

Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
 arch/powerpc/include/asm/fsl_pm.h             |  24 ++
 arch/powerpc/kernel/asm-offsets.c             |  12 +
 arch/powerpc/kernel/fsl_booke_entry_mapping.S |  10 +
 arch/powerpc/kernel/head_64.S                 |   2 +-
 arch/powerpc/platforms/85xx/Makefile          |   1 +
 arch/powerpc/platforms/85xx/deepsleep.c       | 278 ++++++++++++++
 arch/powerpc/platforms/85xx/qoriq_pm.c        |  25 ++
 arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 ++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_rcpm.c                |   8 +-
 9 files changed, 889 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
 create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S

diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
index e05049b..48c2631 100644
--- a/arch/powerpc/include/asm/fsl_pm.h
+++ b/arch/powerpc/include/asm/fsl_pm.h
@@ -20,6 +20,7 @@
 
 #define PLAT_PM_SLEEP	20
 #define PLAT_PM_LPM20	30
+#define PLAT_PM_LPM35	40
 
 #define FSL_PM_SLEEP		(1 << 0)
 #define FSL_PM_DEEP_SLEEP	(1 << 1)
@@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
 
 int __init fsl_rcpm_init(void);
 
+#ifdef CONFIG_FSL_QORIQ_PM
+int fsl_enter_deepsleep(void);
+int fsl_deepsleep_init(void);
+#else
+static inline int fsl_enter_deepsleep(void) { return -1; }
+static inline int fsl_deepsleep_init(void) { return -1; }
+#endif
+
+extern void fsl_dp_enter_low(void *priv);
+extern void fsl_booke_deep_sleep_resume(void);
+
+struct fsl_iomap {
+	void *ccsr_scfg_base;
+	void *ccsr_rcpm_base;
+	void *ccsr_ddr_base;
+	void *ccsr_gpio1_base;
+	void *ccsr_cpc_base;
+	void *dcsr_epu_base;
+	void *dcsr_npc_base;
+	void *dcsr_rcpm_base;
+	void *cpld_base;
+	void *fpga_base;
+};
 #endif /* __PPC_FSL_PM_H */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 9ea0955..cc488f9 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -68,6 +68,10 @@
 #include "../mm/mmu_decl.h"
 #endif
 
+#ifdef CONFIG_FSL_QORIQ_PM
+#include <asm/fsl_pm.h>
+#endif
+
 int main(void)
 {
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
@@ -783,5 +787,13 @@ int main(void)
 
 	DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER);
 
+#ifdef CONFIG_FSL_QORIQ_PM
+	DEFINE(CCSR_CPC_BASE, offsetof(struct fsl_iomap, ccsr_cpc_base));
+	DEFINE(CCSR_GPIO1_BASE, offsetof(struct fsl_iomap, ccsr_gpio1_base));
+	DEFINE(CCSR_RCPM_BASE, offsetof(struct fsl_iomap, ccsr_rcpm_base));
+	DEFINE(CCSR_DDR_BASE, offsetof(struct fsl_iomap, ccsr_ddr_base));
+	DEFINE(CCSR_SCFG_BASE, offsetof(struct fsl_iomap, ccsr_scfg_base));
+	DEFINE(DCSR_EPU_BASE, offsetof(struct fsl_iomap, dcsr_epu_base));
+#endif
 	return 0;
 }
diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
index 83dd0f6..659b059 100644
--- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
+++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
@@ -173,6 +173,10 @@ skpinv:	addi	r6,r6,1				/* Increment */
 	lis	r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
 	ori	r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@l
 	mtspr	SPRN_MAS2,r6
+#ifdef ENTRY_DEEPSLEEP_SETUP
+	LOAD_REG_IMMEDIATE(r8, MEMORY_START)
+	ori	r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
+#endif
 	mtspr	SPRN_MAS3,r8
 	tlbwe
 
@@ -215,12 +219,18 @@ next_tlb_setup:
 	#error You need to specify the mapping or not use this at all.
 #endif
 
+#ifdef ENTRY_DEEPSLEEP_SETUP
+	LOAD_REG_ADDR(r6, 2f)
+	mfmsr	r7
+	rlwinm	r7,r7,0,~(MSR_IS|MSR_DS)
+#else
 	lis	r7,MSR_KERNEL@h
 	ori	r7,r7,MSR_KERNEL@l
 	bl	1f			/* Find our address */
 1:	mflr	r9
 	rlwimi	r6,r9,0,20,31
 	addi	r6,r6,(2f - 1b)
+#endif
 	mtspr	SPRN_SRR0,r6
 	mtspr	SPRN_SRR1,r7
 	rfi				/* start execution out of TLB1[0] entry */
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 2d14774..21fa124 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -829,7 +829,7 @@ _GLOBAL(start_secondary_resume)
 /*
  * This subroutine clobbers r11 and r12
  */
-enable_64b_mode:
+_GLOBAL(enable_64b_mode)
 	mfmsr	r11			/* grab the current MSR */
 #ifdef CONFIG_PPC_BOOK3E
 	oris	r11,r11,0x8000		/* CM bit set, we'll set ICM later */
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 87fb847..a73d563 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -4,6 +4,7 @@
 obj-$(CONFIG_SMP) += smp.o
 obj-$(CONFIG_FSL_PMC)		  += mpc85xx_pm_ops.o
 obj-$(CONFIG_FSL_QORIQ_PM)	  += qoriq_pm.o sleep_fsm.o
+obj-$(CONFIG_FSL_QORIQ_PM)	  += deepsleep.o t104x_deepsleep.o
 
 obj-y += common.o
 
diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c
new file mode 100644
index 0000000..9521d99
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/deepsleep.c
@@ -0,0 +1,278 @@
+/*
+ * Support deep sleep feature for T104x
+ *
+ * Copyright 2016 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@nxp.com>
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/machdep.h>
+#include <asm/fsl_pm.h>
+
+#include "sleep_fsm.h"
+
+#define CPC_CPCHDBCR0		0x0f00
+#define CPC_CPCHDBCR0_SPEC_DIS	0x08000000
+
+#define CCSR_SCFG_DPSLPCR	0x000
+#define CCSR_SCFG_DPSLPCR_WDRR_EN	0x1
+#define CCSR_SCFG_SPARECR2	0x504
+#define CCSR_SCFG_SPARECR3	0x508
+
+#define CCSR_GPIO1_GPDIR	0x000
+#define CCSR_GPIO1_GPODR	0x004
+#define CCSR_GPIO1_GPDAT	0x008
+
+#define QIXIS_PWR_CTL2		0x21
+#define QIXIS_PWR_CTL2_PCTL	0x2
+
+#define QORIQ_CPLD_MISCCSR		0x17
+#define QORIQ_CPLD_MISCCSR_SLEEPEN	0x40
+
+/* 128 bytes buffer for restoring data broke by DDR training initialization */
+#define DDR_BUF_SIZE	128
+static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
+static int fsl_gpio_mcke;
+
+static void fsl_dp_iounmap(void);
+
+static struct fsl_iomap fsl_dp_priv;
+
+static const struct of_device_id fsl_dp_cpld_ids[] __initconst = {
+	{ .compatible = "fsl,t1024-cpld", },
+	{ .compatible = "fsl,t1040rdb-cpld", },
+	{ .compatible = "fsl,t1042rdb-cpld", },
+	{ .compatible = "fsl,t1042rdb_pi-cpld", },
+	{ .compatible = "fsl,t1040d4rdb-cpld", },
+	{}
+};
+
+static const struct of_device_id fsl_dp_fpga_ids[] __initconst = {
+	{ .compatible = "fsl,fpga-qixis", },
+	{ .compatible = "fsl,tetra-fpga", },
+	{}
+};
+
+static void fsl_dp_set_resume_pointer(void)
+{
+	u32 resume_addr;
+
+	/* the bootloader will finally jump to this address to return kernel */
+#ifdef CONFIG_PPC32
+	resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
+#else
+	resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
+			    & 0xffffffff);
+#endif
+
+	/* use the register SPARECR2 to save the resume address */
+	out_be32(fsl_dp_priv.ccsr_scfg_base + CCSR_SCFG_SPARECR2,
+							resume_addr);
+}
+
+static void fsl_dp_pins_setup(void)
+{
+	u32 mask = BIT(31 - fsl_gpio_mcke);
+
+	/* set GPIO1_29 as an output pin (not open-drain), and output 0 */
+	clrbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPDAT, mask);
+	clrbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPODR, mask);
+	setbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPDIR, mask);
+
+	/* wait for the stabilization of GPIO1_29 */
+	udelay(10);
+
+	/* enable the functionality of pins relevant to deep sleep */
+	if (fsl_dp_priv.cpld_base) {
+		setbits8(fsl_dp_priv.cpld_base + QORIQ_CPLD_MISCCSR,
+			 QORIQ_CPLD_MISCCSR_SLEEPEN);
+	} else if (fsl_dp_priv.fpga_base) {
+		setbits8(fsl_dp_priv.fpga_base + QIXIS_PWR_CTL2,
+			 QIXIS_PWR_CTL2_PCTL);
+	}
+}
+
+static void fsl_dp_ddr_save(void *scfg_base)
+{
+	u32 ddr_buff_addr;
+
+	/*
+	 * DDR training initialization will break 128 bytes at the beginning
+	 * of DDR, therefore, save them so that the bootloader will restore
+	 * them. Assume that DDR is mapped to the address space started with
+	 * CONFIG_PAGE_OFFSET.
+	 */
+	memcpy(ddr_buff, (void *)CONFIG_PAGE_OFFSET, DDR_BUF_SIZE);
+
+	/* assume ddr_buff is in the physical address space of 4GB */
+	ddr_buff_addr = (u32)(__pa(ddr_buff) & 0xffffffff);
+
+	/*
+	 * the bootloader will restore the first 128 bytes of DDR from
+	 * the location indicated by the register SPARECR3
+	 */
+	out_be32(scfg_base + CCSR_SCFG_SPARECR3, ddr_buff_addr);
+}
+
+int fsl_enter_deepsleep(void)
+{
+	fsl_dp_ddr_save(fsl_dp_priv.ccsr_scfg_base);
+
+	fsl_dp_set_resume_pointer();
+
+	/*  enable Warm Device Reset request. */
+	setbits32(fsl_dp_priv.ccsr_scfg_base + CCSR_SCFG_DPSLPCR,
+					CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+	/*
+	 * Disable CPC speculation to avoid deep sleep hang, especially
+	 * in secure boot mode. This bit will be cleared automatically
+	 * when resuming from deep sleep.
+	 */
+	setbits32(fsl_dp_priv.ccsr_cpc_base + CPC_CPCHDBCR0,
+					CPC_CPCHDBCR0_SPEC_DIS);
+
+	fsl_epu_setup_default(fsl_dp_priv.dcsr_epu_base);
+	fsl_npc_setup_default(fsl_dp_priv.dcsr_npc_base);
+	fsl_dcsr_rcpm_setup(fsl_dp_priv.dcsr_rcpm_base);
+
+	fsl_dp_pins_setup();
+
+	fsl_dp_enter_low(&fsl_dp_priv);
+
+	/* disable Warm Device Reset request */
+	clrbits32(fsl_dp_priv.ccsr_scfg_base + CCSR_SCFG_DPSLPCR,
+					CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+	fsl_epu_clean_default(fsl_dp_priv.dcsr_epu_base);
+
+	return 0;
+}
+
+static void __init *fsl_of_iomap(char *comp)
+{
+	struct device_node *np;
+	void *addr;
+
+	np = of_find_compatible_node(NULL, NULL, comp);
+	if (np) {
+		addr = of_iomap(np, 0);
+		of_node_put(np);
+		return addr;
+	}
+
+	return NULL;
+}
+
+static struct device_node __init *fsl_get_gpio_node(void)
+{
+	struct device_node *np;
+	u32 val[3];
+	int ret;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.1");
+	ret = of_property_read_u32_array(np, "mcke-gpios", val, 3);
+	if (ret)
+		return NULL;
+
+	fsl_gpio_mcke = val[1];
+	np = of_find_node_by_phandle((phandle)val[0]);
+	if (!np)
+		return NULL;
+
+	return np;
+}
+
+static int __init fsl_dp_iomap(void)
+{
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, fsl_dp_cpld_ids);
+	if (np) {
+		fsl_dp_priv.cpld_base = of_iomap(np, 0);
+		of_node_put(np);
+	} else {
+		np = of_find_matching_node(NULL, fsl_dp_fpga_ids);
+		if (np) {
+			fsl_dp_priv.fpga_base = of_iomap(np, 0);
+			of_node_put(np);
+		} else
+			goto err;
+	}
+
+	fsl_dp_priv.ccsr_scfg_base = fsl_of_iomap("fsl,t1040-scfg");
+	if (!fsl_dp_priv.ccsr_scfg_base) {
+		fsl_dp_priv.ccsr_scfg_base = fsl_of_iomap("fsl,t1023-scfg");
+		if (!fsl_dp_priv.ccsr_scfg_base)
+			goto err;
+	}
+
+	fsl_dp_priv.ccsr_rcpm_base = fsl_of_iomap("fsl,qoriq-rcpm-2.1");
+	if (!fsl_dp_priv.ccsr_rcpm_base)
+		goto err;
+
+	fsl_dp_priv.ccsr_ddr_base = fsl_of_iomap("fsl,qoriq-memory-controller");
+	if (!fsl_dp_priv.ccsr_ddr_base)
+		goto err;
+
+	np = fsl_get_gpio_node();
+	fsl_dp_priv.ccsr_gpio1_base = of_iomap(np, 0);
+	if (!fsl_dp_priv.ccsr_gpio1_base)
+		goto err;
+
+	fsl_dp_priv.ccsr_cpc_base =
+			fsl_of_iomap("fsl,t1040-l3-cache-controller");
+	if (!fsl_dp_priv.ccsr_cpc_base) {
+		fsl_dp_priv.ccsr_cpc_base =
+			fsl_of_iomap("fsl,t1023-l3-cache-controlle");
+		if (!fsl_dp_priv.ccsr_cpc_base)
+			goto err;
+	}
+
+	fsl_dp_priv.dcsr_epu_base = fsl_of_iomap("fsl,dcsr-epu");
+	if (!fsl_dp_priv.dcsr_epu_base)
+		goto err;
+
+	fsl_dp_priv.dcsr_npc_base = fsl_of_iomap("fsl,dcsr-cnpc");
+	if (!fsl_dp_priv.dcsr_npc_base)
+		goto err;
+
+	fsl_dp_priv.dcsr_rcpm_base = fsl_of_iomap("fsl,dcsr-rcpm");
+	if (!fsl_dp_priv.dcsr_rcpm_base)
+		goto err;
+
+	return 0;
+
+err:
+	fsl_dp_iounmap();
+	return -1;
+}
+
+static void __init fsl_dp_iounmap(void)
+{
+	void **p = (void *)&fsl_dp_priv;
+	int i;
+
+	for (i = 0; i < sizeof(struct fsl_iomap)/sizeof(void *); i++) {
+		iounmap(*p);
+		*p = NULL;
+		p++;
+	}
+}
+
+int __init fsl_deepsleep_init(void)
+{
+	return fsl_dp_iomap();
+}
diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
index c97ef8f..ff6e46a 100644
--- a/arch/powerpc/platforms/85xx/qoriq_pm.c
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/suspend.h>
 #include <linux/of_platform.h>
+#include <linux/of_fdt.h>
 
 #include <asm/fsl_pm.h>
 
@@ -27,6 +28,11 @@ static int qoriq_suspend_enter(suspend_state_t state)
 	case PM_SUSPEND_STANDBY:
 		ret = qoriq_pm_ops->plat_enter_sleep(FSL_PM_SLEEP);
 		break;
+
+	case PM_SUSPEND_MEM:
+		ret = qoriq_pm_ops->plat_enter_sleep(FSL_PM_DEEP_SLEEP);
+		break;
+
 	default:
 		ret = -EINVAL;
 	}
@@ -40,9 +46,24 @@ static int qoriq_suspend_valid(suspend_state_t state)
 	if (state == PM_SUSPEND_STANDBY && (pm_modes & FSL_PM_SLEEP))
 		return 1;
 
+	if (state == PM_SUSPEND_MEM && (pm_modes & FSL_PM_DEEP_SLEEP))
+		return 1;
+
 	return 0;
 }
 
+static const char * const boards_deepsleep[] __initconst = {
+	"fsl,T1024QDS",
+	"fsl,T1024RDB",
+	"fsl,T1040QDS",
+	"fsl,T1040RDB",
+	"fsl,T1040D4RDB",
+	"fsl,T1042QDS",
+	"fsl,T1042D4RDB",
+	"fsl,T1042RDB",
+	"fsl,T1042RDB_PI",
+};
+
 static const struct platform_suspend_ops qoriq_suspend_ops = {
 	.valid = qoriq_suspend_valid,
 	.enter = qoriq_suspend_enter,
@@ -53,6 +74,10 @@ static int __init qoriq_suspend_init(void)
 	/* support sleep by default */
 	pm_modes |= FSL_PM_SLEEP;
 
+	if (of_flat_dt_match(of_get_flat_dt_root(), boards_deepsleep) &&
+	    !fsl_deepsleep_init())
+		pm_modes |= FSL_PM_DEEP_SLEEP;
+
 	suspend_set_ops(&qoriq_suspend_ops);
 	return 0;
 }
diff --git a/arch/powerpc/platforms/85xx/t104x_deepsleep.S b/arch/powerpc/platforms/85xx/t104x_deepsleep.S
new file mode 100644
index 0000000..aefce20
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/t104x_deepsleep.S
@@ -0,0 +1,531 @@
+/*
+ * Enter and resume from deep sleep state
+ *
+ * Copyright 2016 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute	it and/or modify it
+ * under  the terms of	the GNU General	 Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+#include <asm/mmu.h>
+
+/*
+ * the number of bytes occupied by one register
+ * the value of 8 is compatible with both 32-bit and 64-bit registers
+ */
+#define STRIDE_SIZE		8
+
+/* GPR0 - GPR31 */
+#define BOOKE_GPR0_OFF		0x0000
+#define BOOKE_GPR_COUNT		32
+/* IVOR0 - IVOR42 */
+#define BOOKE_IVOR0_OFF	   (BOOKE_GPR0_OFF + BOOKE_GPR_COUNT * STRIDE_SIZE)
+#define BOOKE_IVOR_COUNT	43
+/* SPRG0 - SPRG9 */
+#define BOOKE_SPRG0_OFF	   (BOOKE_IVOR0_OFF + BOOKE_IVOR_COUNT * STRIDE_SIZE)
+#define BOOKE_SPRG_COUNT	10
+/* IVPR */
+#define BOOKE_IVPR_OFF	   (BOOKE_SPRG0_OFF + BOOKE_SPRG_COUNT * STRIDE_SIZE)
+
+#define BOOKE_LR_OFF		(BOOKE_IVPR_OFF + STRIDE_SIZE)
+#define BOOKE_MSR_OFF		(BOOKE_LR_OFF + STRIDE_SIZE)
+#define BOOKE_TBU_OFF		(BOOKE_MSR_OFF + STRIDE_SIZE)
+#define BOOKE_TBL_OFF		(BOOKE_TBU_OFF + STRIDE_SIZE)
+#define BOOKE_EPCR_OFF		(BOOKE_TBL_OFF + STRIDE_SIZE)
+#define BOOKE_HID0_OFF		(BOOKE_EPCR_OFF + STRIDE_SIZE)
+#define BOOKE_PIR_OFF		(BOOKE_HID0_OFF + STRIDE_SIZE)
+#define BOOKE_PID0_OFF		(BOOKE_PIR_OFF + STRIDE_SIZE)
+#define BOOKE_BUCSR_OFF		(BOOKE_PID0_OFF + STRIDE_SIZE)
+
+#define BUFFER_SIZE		(BOOKE_BUCSR_OFF + STRIDE_SIZE)
+
+#undef SAVE_GPR
+#define SAVE_GPR(gpr, offset) \
+	PPC_STL gpr, offset(r10)
+
+#define RESTORE_GPR(gpr, offset) \
+	PPC_LL gpr, offset(r10)
+
+#define SAVE_SPR(spr, offset)	\
+	mfspr	r0, spr;	\
+	PPC_STL	r0, offset(r10)
+
+#define RESTORE_SPR(spr, offset) \
+	PPC_LL	r0, offset(r10); \
+	mtspr	spr, r0
+
+#define SAVE_ALL_GPR \
+	SAVE_GPR(r1, BOOKE_GPR0_OFF + STRIDE_SIZE * 1) ;\
+	SAVE_GPR(r2, BOOKE_GPR0_OFF + STRIDE_SIZE * 2) ;\
+	SAVE_GPR(r13, BOOKE_GPR0_OFF + STRIDE_SIZE * 13) ;\
+	SAVE_GPR(r14, BOOKE_GPR0_OFF + STRIDE_SIZE * 14) ;\
+	SAVE_GPR(r15, BOOKE_GPR0_OFF + STRIDE_SIZE * 15) ;\
+	SAVE_GPR(r16, BOOKE_GPR0_OFF + STRIDE_SIZE * 16) ;\
+	SAVE_GPR(r17, BOOKE_GPR0_OFF + STRIDE_SIZE * 17) ;\
+	SAVE_GPR(r18, BOOKE_GPR0_OFF + STRIDE_SIZE * 18) ;\
+	SAVE_GPR(r19, BOOKE_GPR0_OFF + STRIDE_SIZE * 19) ;\
+	SAVE_GPR(r20, BOOKE_GPR0_OFF + STRIDE_SIZE * 20) ;\
+	SAVE_GPR(r21, BOOKE_GPR0_OFF + STRIDE_SIZE * 21) ;\
+	SAVE_GPR(r22, BOOKE_GPR0_OFF + STRIDE_SIZE * 22) ;\
+	SAVE_GPR(r23, BOOKE_GPR0_OFF + STRIDE_SIZE * 23) ;\
+	SAVE_GPR(r24, BOOKE_GPR0_OFF + STRIDE_SIZE * 24) ;\
+	SAVE_GPR(r25, BOOKE_GPR0_OFF + STRIDE_SIZE * 25) ;\
+	SAVE_GPR(r26, BOOKE_GPR0_OFF + STRIDE_SIZE * 26) ;\
+	SAVE_GPR(r27, BOOKE_GPR0_OFF + STRIDE_SIZE * 27) ;\
+	SAVE_GPR(r28, BOOKE_GPR0_OFF + STRIDE_SIZE * 28) ;\
+	SAVE_GPR(r29, BOOKE_GPR0_OFF + STRIDE_SIZE * 29) ;\
+	SAVE_GPR(r30, BOOKE_GPR0_OFF + STRIDE_SIZE * 30) ;\
+	SAVE_GPR(r31, BOOKE_GPR0_OFF + STRIDE_SIZE * 31)
+
+#define RESTORE_ALL_GPR \
+	RESTORE_GPR(r1, BOOKE_GPR0_OFF + STRIDE_SIZE * 1) ;\
+	RESTORE_GPR(r2, BOOKE_GPR0_OFF + STRIDE_SIZE * 2) ;\
+	RESTORE_GPR(r13, BOOKE_GPR0_OFF + STRIDE_SIZE * 13) ;\
+	RESTORE_GPR(r14, BOOKE_GPR0_OFF + STRIDE_SIZE * 14) ;\
+	RESTORE_GPR(r15, BOOKE_GPR0_OFF + STRIDE_SIZE * 15) ;\
+	RESTORE_GPR(r16, BOOKE_GPR0_OFF + STRIDE_SIZE * 16) ;\
+	RESTORE_GPR(r17, BOOKE_GPR0_OFF + STRIDE_SIZE * 17) ;\
+	RESTORE_GPR(r18, BOOKE_GPR0_OFF + STRIDE_SIZE * 18) ;\
+	RESTORE_GPR(r19, BOOKE_GPR0_OFF + STRIDE_SIZE * 19) ;\
+	RESTORE_GPR(r20, BOOKE_GPR0_OFF + STRIDE_SIZE * 20) ;\
+	RESTORE_GPR(r21, BOOKE_GPR0_OFF + STRIDE_SIZE * 21) ;\
+	RESTORE_GPR(r22, BOOKE_GPR0_OFF + STRIDE_SIZE * 22) ;\
+	RESTORE_GPR(r23, BOOKE_GPR0_OFF + STRIDE_SIZE * 23) ;\
+	RESTORE_GPR(r24, BOOKE_GPR0_OFF + STRIDE_SIZE * 24) ;\
+	RESTORE_GPR(r25, BOOKE_GPR0_OFF + STRIDE_SIZE * 25) ;\
+	RESTORE_GPR(r26, BOOKE_GPR0_OFF + STRIDE_SIZE * 26) ;\
+	RESTORE_GPR(r27, BOOKE_GPR0_OFF + STRIDE_SIZE * 27) ;\
+	RESTORE_GPR(r28, BOOKE_GPR0_OFF + STRIDE_SIZE * 28) ;\
+	RESTORE_GPR(r29, BOOKE_GPR0_OFF + STRIDE_SIZE * 29) ;\
+	RESTORE_GPR(r30, BOOKE_GPR0_OFF + STRIDE_SIZE * 30) ;\
+	RESTORE_GPR(r31, BOOKE_GPR0_OFF + STRIDE_SIZE * 31)
+
+#define SAVE_ALL_SPRG \
+	SAVE_SPR(SPRN_SPRG0, BOOKE_SPRG0_OFF + STRIDE_SIZE * 0) ;\
+	SAVE_SPR(SPRN_SPRG1, BOOKE_SPRG0_OFF + STRIDE_SIZE * 1) ;\
+	SAVE_SPR(SPRN_SPRG2, BOOKE_SPRG0_OFF + STRIDE_SIZE * 2) ;\
+	SAVE_SPR(SPRN_SPRG3, BOOKE_SPRG0_OFF + STRIDE_SIZE * 3) ;\
+	SAVE_SPR(SPRN_SPRG4, BOOKE_SPRG0_OFF + STRIDE_SIZE * 4) ;\
+	SAVE_SPR(SPRN_SPRG5, BOOKE_SPRG0_OFF + STRIDE_SIZE * 5) ;\
+	SAVE_SPR(SPRN_SPRG6, BOOKE_SPRG0_OFF + STRIDE_SIZE * 6) ;\
+	SAVE_SPR(SPRN_SPRG7, BOOKE_SPRG0_OFF + STRIDE_SIZE * 7) ;\
+	SAVE_SPR(SPRN_SPRG8, BOOKE_SPRG0_OFF + STRIDE_SIZE * 8) ;\
+	SAVE_SPR(SPRN_SPRG9, BOOKE_SPRG0_OFF + STRIDE_SIZE * 9)
+
+#define RESTORE_ALL_SPRG \
+	RESTORE_SPR(SPRN_SPRG0, BOOKE_SPRG0_OFF + STRIDE_SIZE * 0) ;\
+	RESTORE_SPR(SPRN_SPRG1, BOOKE_SPRG0_OFF + STRIDE_SIZE * 1) ;\
+	RESTORE_SPR(SPRN_SPRG2, BOOKE_SPRG0_OFF + STRIDE_SIZE * 2) ;\
+	RESTORE_SPR(SPRN_SPRG3, BOOKE_SPRG0_OFF + STRIDE_SIZE * 3) ;\
+	RESTORE_SPR(SPRN_SPRG4, BOOKE_SPRG0_OFF + STRIDE_SIZE * 4) ;\
+	RESTORE_SPR(SPRN_SPRG5, BOOKE_SPRG0_OFF + STRIDE_SIZE * 5) ;\
+	RESTORE_SPR(SPRN_SPRG6, BOOKE_SPRG0_OFF + STRIDE_SIZE * 6) ;\
+	RESTORE_SPR(SPRN_SPRG7, BOOKE_SPRG0_OFF + STRIDE_SIZE * 7) ;\
+	RESTORE_SPR(SPRN_SPRG8, BOOKE_SPRG0_OFF + STRIDE_SIZE * 8) ;\
+	RESTORE_SPR(SPRN_SPRG9, BOOKE_SPRG0_OFF + STRIDE_SIZE * 9)
+
+#define SAVE_ALL_IVOR \
+	SAVE_SPR(SPRN_IVOR0, BOOKE_IVOR0_OFF + STRIDE_SIZE * 0) ;\
+	SAVE_SPR(SPRN_IVOR1, BOOKE_IVOR0_OFF + STRIDE_SIZE * 1) ;\
+	SAVE_SPR(SPRN_IVOR2, BOOKE_IVOR0_OFF + STRIDE_SIZE * 2) ;\
+	SAVE_SPR(SPRN_IVOR3, BOOKE_IVOR0_OFF + STRIDE_SIZE * 3) ;\
+	SAVE_SPR(SPRN_IVOR4, BOOKE_IVOR0_OFF + STRIDE_SIZE * 4) ;\
+	SAVE_SPR(SPRN_IVOR5, BOOKE_IVOR0_OFF + STRIDE_SIZE * 5) ;\
+	SAVE_SPR(SPRN_IVOR6, BOOKE_IVOR0_OFF + STRIDE_SIZE * 6) ;\
+	SAVE_SPR(SPRN_IVOR7, BOOKE_IVOR0_OFF + STRIDE_SIZE * 7) ;\
+	SAVE_SPR(SPRN_IVOR8, BOOKE_IVOR0_OFF + STRIDE_SIZE * 8) ;\
+	SAVE_SPR(SPRN_IVOR9, BOOKE_IVOR0_OFF + STRIDE_SIZE * 9) ;\
+	SAVE_SPR(SPRN_IVOR10, BOOKE_IVOR0_OFF + STRIDE_SIZE * 10) ;\
+	SAVE_SPR(SPRN_IVOR11, BOOKE_IVOR0_OFF + STRIDE_SIZE * 11) ;\
+	SAVE_SPR(SPRN_IVOR12, BOOKE_IVOR0_OFF + STRIDE_SIZE * 12) ;\
+	SAVE_SPR(SPRN_IVOR13, BOOKE_IVOR0_OFF + STRIDE_SIZE * 13) ;\
+	SAVE_SPR(SPRN_IVOR14, BOOKE_IVOR0_OFF + STRIDE_SIZE * 14) ;\
+	SAVE_SPR(SPRN_IVOR15, BOOKE_IVOR0_OFF + STRIDE_SIZE * 15) ;\
+	SAVE_SPR(SPRN_IVOR35, BOOKE_IVOR0_OFF + STRIDE_SIZE * 35) ;\
+	SAVE_SPR(SPRN_IVOR36, BOOKE_IVOR0_OFF + STRIDE_SIZE * 36) ;\
+	SAVE_SPR(SPRN_IVOR37, BOOKE_IVOR0_OFF + STRIDE_SIZE * 37) ;\
+	SAVE_SPR(SPRN_IVOR38, BOOKE_IVOR0_OFF + STRIDE_SIZE * 38) ;\
+	SAVE_SPR(SPRN_IVOR39, BOOKE_IVOR0_OFF + STRIDE_SIZE * 39) ;\
+	SAVE_SPR(SPRN_IVOR40, BOOKE_IVOR0_OFF + STRIDE_SIZE * 40) ;\
+	SAVE_SPR(SPRN_IVOR41, BOOKE_IVOR0_OFF + STRIDE_SIZE * 41)
+
+#define RESTORE_ALL_IVOR \
+	RESTORE_SPR(SPRN_IVOR0, BOOKE_IVOR0_OFF + STRIDE_SIZE * 0) ;\
+	RESTORE_SPR(SPRN_IVOR1, BOOKE_IVOR0_OFF + STRIDE_SIZE * 1) ;\
+	RESTORE_SPR(SPRN_IVOR2, BOOKE_IVOR0_OFF + STRIDE_SIZE * 2) ;\
+	RESTORE_SPR(SPRN_IVOR3, BOOKE_IVOR0_OFF + STRIDE_SIZE * 3) ;\
+	RESTORE_SPR(SPRN_IVOR4, BOOKE_IVOR0_OFF + STRIDE_SIZE * 4) ;\
+	RESTORE_SPR(SPRN_IVOR5, BOOKE_IVOR0_OFF + STRIDE_SIZE * 5) ;\
+	RESTORE_SPR(SPRN_IVOR6, BOOKE_IVOR0_OFF + STRIDE_SIZE * 6) ;\
+	RESTORE_SPR(SPRN_IVOR7, BOOKE_IVOR0_OFF + STRIDE_SIZE * 7) ;\
+	RESTORE_SPR(SPRN_IVOR8, BOOKE_IVOR0_OFF + STRIDE_SIZE * 8) ;\
+	RESTORE_SPR(SPRN_IVOR9, BOOKE_IVOR0_OFF + STRIDE_SIZE * 9) ;\
+	RESTORE_SPR(SPRN_IVOR10, BOOKE_IVOR0_OFF + STRIDE_SIZE * 10) ;\
+	RESTORE_SPR(SPRN_IVOR11, BOOKE_IVOR0_OFF + STRIDE_SIZE * 11) ;\
+	RESTORE_SPR(SPRN_IVOR12, BOOKE_IVOR0_OFF + STRIDE_SIZE * 12) ;\
+	RESTORE_SPR(SPRN_IVOR13, BOOKE_IVOR0_OFF + STRIDE_SIZE * 13) ;\
+	RESTORE_SPR(SPRN_IVOR14, BOOKE_IVOR0_OFF + STRIDE_SIZE * 14) ;\
+	RESTORE_SPR(SPRN_IVOR15, BOOKE_IVOR0_OFF + STRIDE_SIZE * 15) ;\
+	RESTORE_SPR(SPRN_IVOR35, BOOKE_IVOR0_OFF + STRIDE_SIZE * 35) ;\
+	RESTORE_SPR(SPRN_IVOR36, BOOKE_IVOR0_OFF + STRIDE_SIZE * 36) ;\
+	RESTORE_SPR(SPRN_IVOR37, BOOKE_IVOR0_OFF + STRIDE_SIZE * 37) ;\
+	RESTORE_SPR(SPRN_IVOR38, BOOKE_IVOR0_OFF + STRIDE_SIZE * 38) ;\
+	RESTORE_SPR(SPRN_IVOR39, BOOKE_IVOR0_OFF + STRIDE_SIZE * 39) ;\
+	RESTORE_SPR(SPRN_IVOR40, BOOKE_IVOR0_OFF + STRIDE_SIZE * 40) ;\
+	RESTORE_SPR(SPRN_IVOR41, BOOKE_IVOR0_OFF + STRIDE_SIZE * 41)
+
+/* reset time base to prevent from overflow */
+#define DELAY(count)		\
+	li	r3, count;	\
+	li	r4, 0;		\
+	mtspr	SPRN_TBWL, r4;	\
+101:	mfspr	r4, SPRN_TBRL;	\
+	cmpw	r4, r3;		\
+	blt	101b
+
+#define FSL_DIS_ALL_IRQ		\
+	mfmsr	r8;			\
+	rlwinm	r8, r8, 0, ~MSR_CE;	\
+	rlwinm	r8, r8, 0, ~MSR_ME;	\
+	rlwinm	r8, r8, 0, ~MSR_EE;	\
+	rlwinm	r8, r8, 0, ~MSR_DE;	\
+	mtmsr	r8;			\
+	isync
+
+	.section .data
+	.align	6
+regs_buffer:
+	.space BUFFER_SIZE
+
+	.section .text
+/*
+ * Save CPU registers
+ * r3 : the base address of the buffer which stores the values of registers
+ */
+e5500_cpu_state_save:
+	/* store the base address to r10 */
+	mr	r10, r3
+
+	SAVE_ALL_GPR
+	SAVE_ALL_SPRG
+	SAVE_ALL_IVOR
+
+	SAVE_SPR(SPRN_IVPR, BOOKE_IVPR_OFF)
+	SAVE_SPR(SPRN_PID0, BOOKE_PID0_OFF)
+	SAVE_SPR(SPRN_EPCR, BOOKE_EPCR_OFF)
+	SAVE_SPR(SPRN_HID0, BOOKE_HID0_OFF)
+	SAVE_SPR(SPRN_PIR, BOOKE_PIR_OFF)
+	SAVE_SPR(SPRN_BUCSR, BOOKE_BUCSR_OFF)
+1:
+	mfspr	r5, SPRN_TBRU
+	mfspr	r4, SPRN_TBRL
+	SAVE_GPR(r5, BOOKE_TBU_OFF)
+	SAVE_GPR(r4, BOOKE_TBL_OFF)
+	mfspr	r3, SPRN_TBRU
+	cmpw	r3, r5
+	bne	1b
+
+	blr
+
+/*
+ * Restore CPU registers
+ * r3 : the base address of the buffer which stores the values of registers
+ */
+e5500_cpu_state_restore:
+	/* store the base address to r10 */
+	mr	r10, r3
+
+	RESTORE_ALL_GPR
+	RESTORE_ALL_SPRG
+	RESTORE_ALL_IVOR
+
+	RESTORE_SPR(SPRN_IVPR, BOOKE_IVPR_OFF)
+	RESTORE_SPR(SPRN_PID0, BOOKE_PID0_OFF)
+	RESTORE_SPR(SPRN_EPCR, BOOKE_EPCR_OFF)
+	RESTORE_SPR(SPRN_HID0, BOOKE_HID0_OFF)
+	RESTORE_SPR(SPRN_PIR, BOOKE_PIR_OFF)
+	RESTORE_SPR(SPRN_BUCSR, BOOKE_BUCSR_OFF)
+
+	li	r0, 0
+	mtspr	SPRN_TBWL, r0
+	RESTORE_SPR(SPRN_TBWU, BOOKE_TBU_OFF)
+	RESTORE_SPR(SPRN_TBWL, BOOKE_TBL_OFF)
+
+	blr
+
+#define CPC_CPCCSR0		0x0
+#define CPC_CPCCSR0_CPCFL	0x800
+
+/*
+ * Flush the CPC cache.
+ * r3 : the base address of CPC
+ */
+flush_cpc_cache:
+	lwz	r6, CPC_CPCCSR0(r3)
+	ori	r6, r6, CPC_CPCCSR0_CPCFL
+	stw	r6, CPC_CPCCSR0(r3)
+	sync
+
+	/* Wait until completing the flush */
+1:	lwz	r6, CPC_CPCCSR0(r3)
+	andi.	r6, r6, CPC_CPCCSR0_CPCFL
+	bne	1b
+
+	blr
+
+/*
+ * the last stage to enter deep sleep
+ */
+	.align 6
+_GLOBAL(fsl_dp_enter_low)
+deepsleep_start:
+	LOAD_REG_ADDR(r9, buf_tmp)
+	/* save the return address and MSR */
+	mflr	r8
+	PPC_STL r8, 0(r9)
+	mfmsr	r8
+	PPC_STL r8, 8(r9)
+	mfspr	r8, SPRN_TCR
+	PPC_STL r8, 16(r9)
+	mfcr	r8
+	PPC_STL	r8, 24(r9)
+
+	li	r8, 0
+	mtspr	SPRN_TCR, r8
+
+	/* save the parameters */
+	PPC_STL	r3, 32(r9)
+
+	LOAD_REG_ADDR(r3, regs_buffer)
+	bl	e5500_cpu_state_save
+
+	/* restore the parameters */
+	LOAD_REG_ADDR(r9, buf_tmp)
+	PPC_LL	r31, 32(r9)
+
+	/* flush caches inside CPU */
+	LOAD_REG_ADDR(r3, cur_cpu_spec)
+	PPC_LL	r3, 0(r3)
+	PPC_LL	r3, CPU_DOWN_FLUSH(r3)
+	PPC_LCMPI  0, r3, 0
+	beq	10f
+#ifdef CONFIG_PPC64
+	PPC_LL	r3, 0(r3)
+#endif
+	mtctr	r3
+	bctrl
+10:
+	/* Flush the CPC cache */
+	PPC_LL	r3, CCSR_CPC_BASE(r31)
+	bl	flush_cpc_cache
+
+	/* prefecth TLB */
+#define CCSR_GPIO1_GPDAT	0x0008
+#define CCSR_GPIO1_GPDAT_29	0x4
+	PPC_LL	r11, CCSR_GPIO1_BASE(r31)
+	addi	r11, r11, CCSR_GPIO1_GPDAT
+	lwz	r10, 0(r11)
+
+#define CCSR_RCPM_PCPH15SETR	0x0b4
+#define CCSR_RCPM_PCPH15SETR_CORE0	0x1
+	PPC_LL	r12, CCSR_RCPM_BASE(r31)
+	addi	r12, r12, CCSR_RCPM_PCPH15SETR
+	lwz	r10, 0(r12)
+
+#define CCSR_DDR_SDRAM_CFG_2	0x114
+#define CCSR_DDR_SDRAM_CFG_2_FRC_SR	0x80000000
+	PPC_LL	r13, CCSR_DDR_BASE(r31)
+	addi	r13, r13, CCSR_DDR_SDRAM_CFG_2
+	lwz	r10, 0(r13)
+
+#define	DCSR_EPU_EPGCR		0x000
+#define DCSR_EPU_EPGCR_GCE	0x80000000
+	PPC_LL	r14, DCSR_EPU_BASE(r31)
+	addi	r14, r14, DCSR_EPU_EPGCR
+	lwz	r10, 0(r14)
+
+#define	DCSR_EPU_EPECR15	0x33C
+#define DCSR_EPU_EPECR15_IC0	0x80000000
+	PPC_LL	r15, DCSR_EPU_BASE(r31)
+	addi	r15, r15, DCSR_EPU_EPECR15
+	lwz	r10, 0(r15)
+
+#define CCSR_SCFG_QMIFRSTCR		0x40c
+#define CCSR_SCFG_QMIFRSTCR_QMIFRST	0x80000000
+	PPC_LL	r16, CCSR_SCFG_BASE(r31)
+	addi	r16, r16, CCSR_SCFG_QMIFRSTCR
+	lwz	r10, 0(r16)
+
+	LOAD_REG_ADDR(r8, deepsleep_start)
+	LOAD_REG_ADDR(r9, deepsleep_end)
+
+	/* prefecth code to cache so that executing code after disable DDR */
+1:	icbtls	2, 0, r8
+	addi	r8, r8, 64
+	cmpw	r8, r9
+	blt	1b
+	sync
+
+	FSL_DIS_ALL_IRQ
+
+	/*
+	 * Place DDR controller in self refresh mode.
+	 * From here on, can't access DDR any more.
+	 */
+	lwz	r10, 0(r13)
+	oris	r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
+	stw	r10, 0(r13)
+	lwz	r10, 0(r13)
+	sync
+
+	DELAY(500)
+
+	/*
+	 * Set GPIO1_29 to lock the signal MCKE down during deep sleep.
+	 * The bootloader will clear it when wakeup.
+	 */
+	lwz	r10, 0(r11)
+	ori	r10, r10, CCSR_GPIO1_GPDAT_29
+	stw	r10, 0(r11)
+	lwz	r10, 0(r11)
+
+	DELAY(100)
+
+	/* Reset QMan system bus interface */
+	lwz	r10, 0(r16)
+	oris	r10, r10, CCSR_SCFG_QMIFRSTCR_QMIFRST@h
+	stw	r10, 0(r16)
+	lwz	r10, 0(r16)
+
+	/* Enable all EPU Counters */
+	li	r10, 0
+	oris	r10, r10, DCSR_EPU_EPGCR_GCE@h
+	stw	r10, 0(r14)
+	lwz	r10, 0(r14)
+
+	/* Enable SCU15 to trigger on RCPM Concentrator 0 */
+	lwz	r10, 0(r15)
+	oris	r10, r10, DCSR_EPU_EPECR15_IC0@h
+	stw	r10, 0(r15)
+	lwz	r10, 0(r15)
+
+	/* put Core0 in PH15 mode, trigger EPU FSM */
+	lwz	r10, 0(r12)
+	ori	r10, r10, CCSR_RCPM_PCPH15SETR_CORE0
+	stw	r10, 0(r12)
+2:
+	b 2b
+
+	/*
+	 * Leave some space to prevent prefeching instruction
+	 * beyond deepsleep_end. The space also can be used as heap.
+	 */
+buf_tmp:
+	.space 128
+	.align 6
+deepsleep_end:
+
+	.align 12
+#ifdef CONFIG_PPC32
+_GLOBAL(fsl_booke_deep_sleep_resume)
+	/* disable interrupts */
+	FSL_DIS_ALL_IRQ
+
+#define ENTRY_DEEPSLEEP_SETUP
+#define ENTRY_MAPPING_BOOT_SETUP
+#include <../../kernel/fsl_booke_entry_mapping.S>
+#undef ENTRY_DEEPSLEEP_SETUP
+#undef ENTRY_MAPPING_BOOT_SETUP
+
+	li	r3, 0
+	mfspr   r4, SPRN_PIR
+	bl	call_setup_cpu
+
+	/* Load each CAM entry */
+	LOAD_REG_ADDR(r3, tlbcam_index)
+	lwz	r3, 0(r3)
+	mtctr	r3
+	li	r9, 0
+3:	mr	r3, r9
+	bl	loadcam_entry
+	addi	r9, r9, 1
+	bdnz	3b
+
+	/* restore cpu registers */
+	LOAD_REG_ADDR(r3, regs_buffer)
+	bl	e5500_cpu_state_restore
+
+	/* restore return address */
+	LOAD_REG_ADDR(r3, buf_tmp)
+	lwz	r4, 16(r3)
+	mtspr	SPRN_TCR, r4
+	lwz	r4, 0(r3)
+	mtlr	r4
+	lwz	r4, 8(r3)
+	mtmsr	r4
+	lwz	r4, 24(r3)
+	mtcr	r4
+
+	blr
+
+#else /* CONFIG_PPC32 */
+
+_GLOBAL(fsl_booke_deep_sleep_resume)
+	/* disable interrupts */
+	FSL_DIS_ALL_IRQ
+
+	/* switch to 64-bit mode */
+	bl	.enable_64b_mode
+
+	/* set TOC pointer */
+	bl	.relative_toc
+
+	/* setup initial TLBs, switch to kernel space ... */
+	bl	.start_initialization_book3e
+
+	/* address space changed, set TOC pointer again */
+	bl	.relative_toc
+
+	/* call a cpu state restore handler */
+	LOAD_REG_ADDR(r23, cur_cpu_spec)
+	ld	r23,0(r23)
+	ld	r23,CPU_SPEC_RESTORE(r23)
+	cmpdi	0,r23,0
+	beq	1f
+	ld	r23,0(r23)
+	mtctr	r23
+	bctrl
+1:
+	LOAD_REG_ADDR(r3, regs_buffer)
+	bl	e5500_cpu_state_restore
+
+	/* Load each CAM entry */
+	LOAD_REG_ADDR(r3, tlbcam_index)
+	lwz	r3, 0(r3)
+	mtctr	r3
+	li	r0, 0
+3:	mr	r3, r0
+	bl	loadcam_entry
+	addi	r0, r0, 1
+	bdnz	3b
+
+	/* restore return address */
+	LOAD_REG_ADDR(r3, buf_tmp)
+	ld	r4, 16(r3)
+	mtspr	SPRN_TCR, r4
+	ld	r4, 0(r3)
+	mtlr	r4
+	ld	r4, 8(r3)
+	mtmsr	r4
+	ld	r4, 24(r3)
+	mtcr	r4
+
+	blr
+
+#endif /* CONFIG_PPC32 */
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
index e5447ac..c2d8d37 100644
--- a/arch/powerpc/sysdev/fsl_rcpm.c
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -249,7 +249,7 @@ static int rcpm_v2_plat_enter_sleep(int state)
 {
 	u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr;
 	int ret = 0;
-	int result;
+	int result, cpu;
 
 	switch (state) {
 	case FSL_PM_SLEEP:
@@ -269,6 +269,12 @@ static int rcpm_v2_plat_enter_sleep(int state)
 			ret = -ETIMEDOUT;
 		}
 		break;
+	case FSL_PM_DEEP_SLEEP:
+		cpu = smp_processor_id();
+		rcpm_v2_irq_mask(cpu);
+		ret = fsl_enter_deepsleep();
+		rcpm_v2_irq_unmask(cpu);
+		break;
 	default:
 		pr_warn("Unknown platform PM state (%d)\n", state);
 		ret = -EINVAL;
-- 
1.9.1

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

* [PATCH v3 5/5] powerpc/pm: save and restore registers during deep sleep
  2016-08-02 11:59 [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature Chenhui Zhao
                   ` (3 preceding siblings ...)
  2016-08-02 11:59 ` [PATCH v3 4/5] powerpc/pm: support deep sleep feature on T104x Chenhui Zhao
@ 2016-08-02 11:59 ` Chenhui Zhao
  4 siblings, 0 replies; 11+ messages in thread
From: Chenhui Zhao @ 2016-08-02 11:59 UTC (permalink / raw)
  To: oss, linuxppc-dev, linux-kernel
  Cc: jason.jin, z.chenhui, Chenhui Zhao, Tang Yuantian

Some CCSR registers will lost during deep sleep. Therefore,
should save them before entering deep sleep, and restore them
when resuming from deep sleep.

Signed-off-by: Tang Yuantian <yuantian.tang@nxp.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
 arch/powerpc/include/asm/fsl_pm.h       |   2 +
 arch/powerpc/platforms/85xx/deepsleep.c | 108 +++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
index 48c2631..95601fb 100644
--- a/arch/powerpc/include/asm/fsl_pm.h
+++ b/arch/powerpc/include/asm/fsl_pm.h
@@ -61,7 +61,9 @@ extern void fsl_dp_enter_low(void *priv);
 extern void fsl_booke_deep_sleep_resume(void);
 
 struct fsl_iomap {
+	void *ccsr_lcc_base;
 	void *ccsr_scfg_base;
+	void *ccsr_dcfg_base;
 	void *ccsr_rcpm_base;
 	void *ccsr_ddr_base;
 	void *ccsr_gpio1_base;
diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c
index 9521d99..71987fd 100644
--- a/arch/powerpc/platforms/85xx/deepsleep.c
+++ b/arch/powerpc/platforms/85xx/deepsleep.c
@@ -23,6 +23,8 @@
 
 #include "sleep_fsm.h"
 
+#define CCSR_LAW_OFFSET		0xC00
+
 #define CPC_CPCHDBCR0		0x0f00
 #define CPC_CPCHDBCR0_SPEC_DIS	0x08000000
 
@@ -41,6 +43,17 @@
 #define QORIQ_CPLD_MISCCSR		0x17
 #define QORIQ_CPLD_MISCCSR_SLEEPEN	0x40
 
+#define CCSR_LCC_BSTRH	0x20
+#define CCSR_LCC_BSTRL	0x24
+#define CCSR_LCC_BSTAR	0x28
+
+#define CCSR_DCFG_BRR	0xE4
+
+#define CCSR_RCPM_PCTBENR	0x1A0
+
+/* the target id for the memory complex 1 (MC1) */
+#define MC1_TRGT_ID		0x10
+
 /* 128 bytes buffer for restoring data broke by DDR training initialization */
 #define DDR_BUF_SIZE	128
 static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
@@ -50,6 +63,23 @@ static void fsl_dp_iounmap(void);
 
 static struct fsl_iomap fsl_dp_priv;
 
+struct fsl_ccsr_law {
+	u32	lawbarh;	/* LAWn base address high */
+	u32	lawbarl;	/* LAWn base address low */
+	u32	lawar;		/* LAWn attributes */
+	u32	reserved;
+};
+
+static struct fsl_regs_buffer {
+	u32 bstrh;
+	u32 bstrl;
+	u32 bstar;
+	u32 brr;
+	u32 pctbenr;
+	u32 law_count;
+	void *law_regs;
+} fsl_dp_buffer;
+
 static const struct of_device_id fsl_dp_cpld_ids[] __initconst = {
 	{ .compatible = "fsl,t1024-cpld", },
 	{ .compatible = "fsl,t1040rdb-cpld", },
@@ -65,6 +95,60 @@ static const struct of_device_id fsl_dp_fpga_ids[] __initconst = {
 	{}
 };
 
+static void fsl_regs_save(struct fsl_iomap *base,
+			  struct fsl_regs_buffer *buffer)
+{
+	int i;
+	struct fsl_ccsr_law *src = base->ccsr_lcc_base + CCSR_LAW_OFFSET;
+	struct fsl_ccsr_law *dst = buffer->law_regs;
+
+	buffer->bstrh = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRH);
+	buffer->bstrl = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRL);
+	buffer->bstar = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTAR);
+	buffer->brr = in_be32(base->ccsr_dcfg_base + CCSR_DCFG_BRR);
+	buffer->pctbenr = in_be32(base->ccsr_rcpm_base + CCSR_RCPM_PCTBENR);
+
+	for (i = 0; i < buffer->law_count; i++) {
+		dst->lawbarh = in_be32(&src->lawbarh);
+		dst->lawbarl = in_be32(&src->lawbarl);
+		dst->lawar = in_be32(&src->lawar);
+		dst++;
+		src++;
+	}
+}
+
+static void fsl_regs_restore(struct fsl_iomap *base,
+			     struct fsl_regs_buffer *buffer)
+{
+	int i;
+	u32 attr;
+	struct fsl_ccsr_law *src = buffer->law_regs;
+	struct fsl_ccsr_law *dst = base->ccsr_lcc_base + CCSR_LAW_OFFSET;
+
+	out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRH, buffer->bstrh);
+	out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRL, buffer->bstrl);
+	out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTAR, buffer->bstar);
+	out_be32(base->ccsr_dcfg_base + CCSR_DCFG_BRR, buffer->brr);
+	out_be32(base->ccsr_rcpm_base + CCSR_RCPM_PCTBENR, buffer->pctbenr);
+
+	for (i = 0; i < buffer->law_count; i++) {
+		/*
+		 * If the LAW with the target id of MC1 has been set,
+		 * skip. Because changing it here causes memory
+		 * access error.
+		 */
+		attr = in_be32(&dst->lawar);
+		if (((attr >> 20) & 0xff) == MC1_TRGT_ID)
+			continue;
+		out_be32(&dst->lawar, 0);
+		out_be32(&dst->lawbarl, src->lawbarl);
+		out_be32(&dst->lawbarh, src->lawbarh);
+		out_be32(&dst->lawar, src->lawar);
+		src++;
+		dst++;
+	}
+}
+
 static void fsl_dp_set_resume_pointer(void)
 {
 	u32 resume_addr;
@@ -132,6 +216,8 @@ int fsl_enter_deepsleep(void)
 
 	fsl_dp_set_resume_pointer();
 
+	fsl_regs_save(&fsl_dp_priv, &fsl_dp_buffer);
+
 	/*  enable Warm Device Reset request. */
 	setbits32(fsl_dp_priv.ccsr_scfg_base + CCSR_SCFG_DPSLPCR,
 					CCSR_SCFG_DPSLPCR_WDRR_EN);
@@ -152,6 +238,8 @@ int fsl_enter_deepsleep(void)
 
 	fsl_dp_enter_low(&fsl_dp_priv);
 
+	fsl_regs_restore(&fsl_dp_priv, &fsl_dp_buffer);
+
 	/* disable Warm Device Reset request */
 	clrbits32(fsl_dp_priv.ccsr_scfg_base + CCSR_SCFG_DPSLPCR,
 					CCSR_SCFG_DPSLPCR_WDRR_EN);
@@ -212,6 +300,11 @@ static int __init fsl_dp_iomap(void)
 			goto err;
 	}
 
+	fsl_dp_priv.ccsr_dcfg_base =
+			fsl_of_iomap("fsl,qoriq-device-config-2.0");
+	if (!fsl_dp_priv.ccsr_dcfg_base)
+		goto err;
+
 	fsl_dp_priv.ccsr_scfg_base = fsl_of_iomap("fsl,t1040-scfg");
 	if (!fsl_dp_priv.ccsr_scfg_base) {
 		fsl_dp_priv.ccsr_scfg_base = fsl_of_iomap("fsl,t1023-scfg");
@@ -253,8 +346,21 @@ static int __init fsl_dp_iomap(void)
 	if (!fsl_dp_priv.dcsr_rcpm_base)
 		goto err;
 
-	return 0;
+	fsl_dp_priv.ccsr_lcc_base = fsl_of_iomap("fsl,corenet-law");
+	if (!fsl_dp_priv.ccsr_lcc_base)
+		goto err;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
+	if (of_property_read_u32(np, "fsl,num-laws",
+					&fsl_dp_buffer.law_count))
+		goto err;
 
+	fsl_dp_buffer.law_regs = kcalloc(fsl_dp_buffer.law_count,
+				sizeof(struct fsl_ccsr_law), GFP_KERNEL);
+	if (!fsl_dp_buffer.law_regs)
+		goto err;
+
+	return 0;
 err:
 	fsl_dp_iounmap();
 	return -1;
-- 
1.9.1

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

* Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
  2016-08-02 11:59 ` [PATCH v3 4/5] powerpc/pm: support deep sleep feature on T104x Chenhui Zhao
@ 2016-09-25  7:24   ` Scott Wood
  2016-09-27 11:05     ` C.H. Zhao
  0 siblings, 1 reply; 11+ messages in thread
From: Scott Wood @ 2016-09-25  7:24 UTC (permalink / raw)
  To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, z.chenhui, jason.jin

On Tue, Aug 02, 2016 at 07:59:31PM +0800, Chenhui Zhao wrote:
> T104x has deep sleep feature, which can switch off most parts of
> the SoC when it is in deep sleep mode. This way, it becomes more
> energy-efficient.
> 
> The DDR controller will also be powered off in deep sleep. Therefore,
> the last stage (the latter part of fsl_dp_enter_low) will run without DDR
> access. This piece of code and related TLBs are prefetched in advance.
> 
> Due to the different initialization code between 32-bit and 64-bit, they
> have separate resume entry and precedure.
> 
> The feature supports 32-bit and 64-bit kernel mode.
> 
> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> ---
>  arch/powerpc/include/asm/fsl_pm.h             |  24 ++
>  arch/powerpc/kernel/asm-offsets.c             |  12 +
>  arch/powerpc/kernel/fsl_booke_entry_mapping.S |  10 +
>  arch/powerpc/kernel/head_64.S                 |   2 +-
>  arch/powerpc/platforms/85xx/Makefile          |   1 +
>  arch/powerpc/platforms/85xx/deepsleep.c       | 278 ++++++++++++++
>  arch/powerpc/platforms/85xx/qoriq_pm.c        |  25 ++
>  arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 ++++++++++++++++++++++++++
>  arch/powerpc/sysdev/fsl_rcpm.c                |   8 +-
>  9 files changed, 889 insertions(+), 2 deletions(-)
>  create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
>  create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S
> 
> diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
> index e05049b..48c2631 100644
> --- a/arch/powerpc/include/asm/fsl_pm.h
> +++ b/arch/powerpc/include/asm/fsl_pm.h
> @@ -20,6 +20,7 @@
>  
>  #define PLAT_PM_SLEEP	20
>  #define PLAT_PM_LPM20	30
> +#define PLAT_PM_LPM35	40
>  
>  #define FSL_PM_SLEEP		(1 << 0)
>  #define FSL_PM_DEEP_SLEEP	(1 << 1)
> @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
>  
>  int __init fsl_rcpm_init(void);
>  
> +#ifdef CONFIG_FSL_QORIQ_PM
> +int fsl_enter_deepsleep(void);
> +int fsl_deepsleep_init(void);
> +#else
> +static inline int fsl_enter_deepsleep(void) { return -1; }
> +static inline int fsl_deepsleep_init(void) { return -1; }
> +#endif

Please return proper error codes.

Where can fsl_deepsleep_init() be called without CONFIG_FSL_QORIQ_PM?

> +
> +extern void fsl_dp_enter_low(void *priv);
> +extern void fsl_booke_deep_sleep_resume(void);
> +
> +struct fsl_iomap {
> +	void *ccsr_scfg_base;
> +	void *ccsr_rcpm_base;
> +	void *ccsr_ddr_base;
> +	void *ccsr_gpio1_base;
> +	void *ccsr_cpc_base;
> +	void *dcsr_epu_base;
> +	void *dcsr_npc_base;
> +	void *dcsr_rcpm_base;
> +	void *cpld_base;
> +	void *fpga_base;
> +};

__iomem

>  #endif /* __PPC_FSL_PM_H */
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index 9ea0955..cc488f9 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -68,6 +68,10 @@
>  #include "../mm/mmu_decl.h"
>  #endif
>  
> +#ifdef CONFIG_FSL_QORIQ_PM
> +#include <asm/fsl_pm.h>
> +#endif

I know this file ifdefs headers a lot, but it's generally not good
practice.  Does including this file cause any harm on other platforms?

> diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> index 83dd0f6..659b059 100644
> --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> @@ -173,6 +173,10 @@ skpinv:	addi	r6,r6,1				/* Increment */
>  	lis	r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
>  	ori	r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@l
>  	mtspr	SPRN_MAS2,r6
> +#ifdef ENTRY_DEEPSLEEP_SETUP
> +	LOAD_REG_IMMEDIATE(r8, MEMORY_START)
> +	ori	r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
> +#endif
>  	mtspr	SPRN_MAS3,r8
>  	tlbwe
>  

Have you tried this with a relocatable kernel?

> +static void fsl_dp_set_resume_pointer(void)
> +{
> +	u32 resume_addr;
> +
> +	/* the bootloader will finally jump to this address to return kernel */
> +#ifdef CONFIG_PPC32
> +	resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
> +#else
> +	resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
> +			    & 0xffffffff);
> +#endif

Why are you masking the physical address by 0xffffffff?  Besides the
(u32) cast accomplishing the same thing, wouldn't it be a problem if
(e.g. due to a relocatable kernel) the address is above 4 GiB?

> +static void fsl_dp_pins_setup(void)
> +{
> +	u32 mask = BIT(31 - fsl_gpio_mcke);
> +
> +	/* set GPIO1_29 as an output pin (not open-drain), and output 0 */
> +	clrbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPDAT, mask);
> +	clrbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPODR, mask);
> +	setbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPDIR, mask);
> +
> +	/* wait for the stabilization of GPIO1_29 */
> +	udelay(10);
> +
> +	/* enable the functionality of pins relevant to deep sleep */
> +	if (fsl_dp_priv.cpld_base) {
> +		setbits8(fsl_dp_priv.cpld_base + QORIQ_CPLD_MISCCSR,
> +			 QORIQ_CPLD_MISCCSR_SLEEPEN);
> +	} else if (fsl_dp_priv.fpga_base) {
> +		setbits8(fsl_dp_priv.fpga_base + QIXIS_PWR_CTL2,
> +			 QIXIS_PWR_CTL2_PCTL);
> +	}
> +}

Please use callbacks to handle board-specific things.

> +/* reset time base to prevent from overflow */
> +#define DELAY(count)		\
> +	li	r3, count;	\
> +	li	r4, 0;		\
> +	mtspr	SPRN_TBWL, r4;	\
> +101:	mfspr	r4, SPRN_TBRL;	\
> +	cmpw	r4, r3;		\
> +	blt	101b

Please find a better way of dealing with overflow than writing to the
timebase.

-Scott

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

* Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
  2016-09-25  7:24   ` [v3,4/5] " Scott Wood
@ 2016-09-27 11:05     ` C.H. Zhao
  2016-09-28 20:03       ` Scott Wood
  0 siblings, 1 reply; 11+ messages in thread
From: C.H. Zhao @ 2016-09-27 11:05 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, z.chenhui, Jason Jin


From: Scott Wood <oss@buserror.net>
Sent: Sunday, September 25, 2016 3:24 PM
To: C.H. Zhao
Cc: linuxppc-dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; z.chenhui@gmail.com; Jason Jin
Subject: Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
    
On Tue, Aug 02, 2016 at 07:59:31PM +0800, Chenhui Zhao wrote:
> T104x has deep sleep feature, which can switch off most parts of
> the SoC when it is in deep sleep mode. This way, it becomes more
> energy-efficient.
> 
> The DDR controller will also be powered off in deep sleep. Therefore,
> the last stage (the latter part of fsl_dp_enter_low) will run without DDR
> access. This piece of code and related TLBs are prefetched in advance.
> 
> Due to the different initialization code between 32-bit and 64-bit, they
> have separate resume entry and precedure.
> 
> The feature supports 32-bit and 64-bit kernel mode.
> 
> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> ---
>  arch/powerpc/include/asm/fsl_pm.h             |  24 ++
>  arch/powerpc/kernel/asm-offsets.c             |  12 +
>  arch/powerpc/kernel/fsl_booke_entry_mapping.S |  10 +
>  arch/powerpc/kernel/head_64.S                 |   2 +-
>  arch/powerpc/platforms/85xx/Makefile          |   1 +
>  arch/powerpc/platforms/85xx/deepsleep.c       | 278 ++++++++++++++
>  arch/powerpc/platforms/85xx/qoriq_pm.c        |  25 ++
>  arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 ++++++++++++++++++++++++++
>  arch/powerpc/sysdev/fsl_rcpm.c                |   8 +-
>  9 files changed, 889 insertions(+), 2 deletions(-)
>  create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
>  create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S
> 
> diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
> index e05049b..48c2631 100644
> --- a/arch/powerpc/include/asm/fsl_pm.h
> +++ b/arch/powerpc/include/asm/fsl_pm.h
> @@ -20,6 +20,7 @@
>  
>  #define PLAT_PM_SLEEP        20
>  #define PLAT_PM_LPM20        30
> +#define PLAT_PM_LPM35        40
>  
>  #define FSL_PM_SLEEP         (1 << 0)
>  #define FSL_PM_DEEP_SLEEP    (1 << 1)
> @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
>  
>  int __init fsl_rcpm_init(void);
>  
> +#ifdef CONFIG_FSL_QORIQ_PM
> +int fsl_enter_deepsleep(void);
> +int fsl_deepsleep_init(void);
> +#else
> +static inline int fsl_enter_deepsleep(void) { return -1; }
> +static inline int fsl_deepsleep_init(void) { return -1; }
> +#endif

Please return proper error codes.

Where can fsl_deepsleep_init() be called without CONFIG_FSL_QORIQ_PM?

[Chenhui] I can get rid of the ifdef here. And add it in arch/powerpc/sysdev/fsl_rcpm.c.

> +
> +extern void fsl_dp_enter_low(void *priv);
> +extern void fsl_booke_deep_sleep_resume(void);
> +
> +struct fsl_iomap {
> +     void *ccsr_scfg_base;
> +     void *ccsr_rcpm_base;
> +     void *ccsr_ddr_base;
> +     void *ccsr_gpio1_base;
> +     void *ccsr_cpc_base;
> +     void *dcsr_epu_base;
> +     void *dcsr_npc_base;
> +     void *dcsr_rcpm_base;
> +     void *cpld_base;
> +     void *fpga_base;
> +};

__iomem

[Chenhui] Yes. Will add it.

>  #endif /* __PPC_FSL_PM_H */
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index 9ea0955..cc488f9 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -68,6 +68,10 @@
>  #include "../mm/mmu_decl.h"
>  #endif
>  
> +#ifdef CONFIG_FSL_QORIQ_PM
> +#include <asm/fsl_pm.h>
> +#endif

I know this file ifdefs headers a lot, but it's generally not good
practice.  Does including this file cause any harm on other platforms?

[Chenhui] Not at all. Will remove it.

> diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> index 83dd0f6..659b059 100644
> --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> @@ -173,6 +173,10 @@ skpinv:  addi    r6,r6,1                         /* Increment */
>        lis     r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
>        ori     r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@l
>        mtspr   SPRN_MAS2,r6
> +#ifdef ENTRY_DEEPSLEEP_SETUP
> +     LOAD_REG_IMMEDIATE(r8, MEMORY_START)
> +     ori     r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
> +#endif
>        mtspr   SPRN_MAS3,r8
>        tlbwe
>  

Have you tried this with a relocatable kernel?

[Chenhui] Not yet. Not sure whether it has been supported on QorIQ platform.

> +static void fsl_dp_set_resume_pointer(void)
> +{
> +     u32 resume_addr;
> +
> +     /* the bootloader will finally jump to this address to return kernel */
> +#ifdef CONFIG_PPC32
> +     resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
> +#else
> +     resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
> +                         & 0xffffffff);
> +#endif

Why are you masking the physical address by 0xffffffff?  Besides the
(u32) cast accomplishing the same thing, wouldn't it be a problem if
(e.g. due to a relocatable kernel) the address is above 4 GiB?

[Chenhui] Here, I assumed kernel is below 4 GiB. Maybe I should add a comment here.

> +static void fsl_dp_pins_setup(void)
> +{
> +     u32 mask = BIT(31 - fsl_gpio_mcke);
> +
> +     /* set GPIO1_29 as an output pin (not open-drain), and output 0 */
> +     clrbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPDAT, mask);
> +     clrbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPODR, mask);
> +     setbits32(fsl_dp_priv.ccsr_gpio1_base + CCSR_GPIO1_GPDIR, mask);
> +
> +     /* wait for the stabilization of GPIO1_29 */
> +     udelay(10);
> +
> +     /* enable the functionality of pins relevant to deep sleep */
> +     if (fsl_dp_priv.cpld_base) {
> +             setbits8(fsl_dp_priv.cpld_base + QORIQ_CPLD_MISCCSR,
> +                      QORIQ_CPLD_MISCCSR_SLEEPEN);
> +     } else if (fsl_dp_priv.fpga_base) {
> +             setbits8(fsl_dp_priv.fpga_base + QIXIS_PWR_CTL2,
> +                      QIXIS_PWR_CTL2_PCTL);
> +     }
> +}

Please use callbacks to handle board-specific things.

[Chenhui] Yes. Will do it as you said.

> +/* reset time base to prevent from overflow */
> +#define DELAY(count)         \
> +     li      r3, count;      \
> +     li      r4, 0;          \
> +     mtspr   SPRN_TBWL, r4;  \
> +101: mfspr   r4, SPRN_TBRL;  \
> +     cmpw    r4, r3;         \
> +     blt     101b

Please find a better way of dealing with overflow than writing to the
timebase.

-Scott

[Chenhui] OK. Let me try other way. Thank you for your time.

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

* Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
  2016-09-27 11:05     ` C.H. Zhao
@ 2016-09-28 20:03       ` Scott Wood
  2016-09-29 10:21         ` C.H. Zhao
  0 siblings, 1 reply; 11+ messages in thread
From: Scott Wood @ 2016-09-28 20:03 UTC (permalink / raw)
  To: C.H. Zhao; +Cc: linuxppc-dev, linux-kernel, z.chenhui, Jason Jin

On Tue, 2016-09-27 at 11:05 +0000, C.H. Zhao wrote:
> From: Scott Wood <oss@buserror.net>
> Sent: Sunday, September 25, 2016 3:24 PM
> To: C.H. Zhao
> Cc: linuxppc-dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; z.chenhui@g
> mail.com; Jason Jin
> Subject: Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
>     
> On Tue, Aug 02, 2016 at 07:59:31PM +0800, Chenhui Zhao wrote:
> > 
> > T104x has deep sleep feature, which can switch off most parts of
> > the SoC when it is in deep sleep mode. This way, it becomes more
> > energy-efficient.
> > 
> > The DDR controller will also be powered off in deep sleep. Therefore,
> > the last stage (the latter part of fsl_dp_enter_low) will run without DDR
> > access. This piece of code and related TLBs are prefetched in advance.
> > 
> > Due to the different initialization code between 32-bit and 64-bit, they
> > have separate resume entry and precedure.
> > 
> > The feature supports 32-bit and 64-bit kernel mode.
> > 
> > Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> > ---
> >   arch/powerpc/include/asm/fsl_pm.h             |  24 ++
> >   arch/powerpc/kernel/asm-offsets.c             |  12 +
> >   arch/powerpc/kernel/fsl_booke_entry_mapping.S |  10 +
> >   arch/powerpc/kernel/head_64.S                 |   2 +-
> >   arch/powerpc/platforms/85xx/Makefile          |   1 +
> >   arch/powerpc/platforms/85xx/deepsleep.c       | 278 ++++++++++++++
> >   arch/powerpc/platforms/85xx/qoriq_pm.c        |  25 ++
> >   arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531
> > ++++++++++++++++++++++++++
> >   arch/powerpc/sysdev/fsl_rcpm.c                |   8 +-
> >   9 files changed, 889 insertions(+), 2 deletions(-)
> >   create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> >   create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S
> > 
> > diff --git a/arch/powerpc/include/asm/fsl_pm.h
> > b/arch/powerpc/include/asm/fsl_pm.h
> > index e05049b..48c2631 100644
> > --- a/arch/powerpc/include/asm/fsl_pm.h
> > +++ b/arch/powerpc/include/asm/fsl_pm.h
> > @@ -20,6 +20,7 @@
> >   
> >   #define PLAT_PM_SLEEP        20
> >   #define PLAT_PM_LPM20        30
> > +#define PLAT_PM_LPM35        40
> >   
> >   #define FSL_PM_SLEEP         (1 << 0)
> >   #define FSL_PM_DEEP_SLEEP    (1 << 1)
> > @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
> >   
> >   int __init fsl_rcpm_init(void);
> >   
> > +#ifdef CONFIG_FSL_QORIQ_PM
> > +int fsl_enter_deepsleep(void);
> > +int fsl_deepsleep_init(void);
> > +#else
> > +static inline int fsl_enter_deepsleep(void) { return -1; }
> > +static inline int fsl_deepsleep_init(void) { return -1; }
> > +#endif
> Please return proper error codes.
> 
> Where can fsl_deepsleep_init() be called without CONFIG_FSL_QORIQ_PM?
> 
> [Chenhui] I can get rid of the ifdef here. And add it
> in arch/powerpc/sysdev/fsl_rcpm.c.

No, this is the right place for the ifdef for functions that are called from
code that doesn't depend on CONFIG_FSL_QORIQ_PM.  But fsl_deepsleep_init() is
called from deepsleep.c which is only built with CONFIG_FSL_QORIQ_PM, and it's
hard to picture a scenario where it would be called from elsewhere.

> > diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > index 83dd0f6..659b059 100644
> > --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > @@ -173,6 +173,10 @@ skpinv:  addi    r6,r6,1                         /*
> > Increment */
> >         lis     r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
> >         ori     r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M,
> > M_IF_NEEDED)@l
> >         mtspr   SPRN_MAS2,r6
> > +#ifdef ENTRY_DEEPSLEEP_SETUP
> > +     LOAD_REG_IMMEDIATE(r8, MEMORY_START)
> > +     ori     r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
> > +#endif
> >         mtspr   SPRN_MAS3,r8
> >         tlbwe
> >   
> Have you tried this with a relocatable kernel?
> 
> [Chenhui] Not yet. Not sure whether it has been supported on QorIQ platform.

It is supported, and deep sleep needs to work with it.

> > +static void fsl_dp_set_resume_pointer(void)
> > +{
> > +     u32 resume_addr;
> > +
> > +     /* the bootloader will finally jump to this address to return kernel
> > */
> > +#ifdef CONFIG_PPC32
> > +     resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
> > +#else
> > +     resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
> > +                         & 0xffffffff);
> > +#endif
> Why are you masking the physical address by 0xffffffff?  Besides the
> (u32) cast accomplishing the same thing, wouldn't it be a problem if
> (e.g. due to a relocatable kernel) the address is above 4 GiB?
> 
> [Chenhui] Here, I assumed kernel is below 4 GiB. Maybe I should add a
> comment here.

It needs a fix rather than a comment, unless you can show that the relocatable
mechanism doesn't support kernels over 4 GiB (I don't remember of the top of
my head whether it does).

-Scott

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

* Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
  2016-09-28 20:03       ` Scott Wood
@ 2016-09-29 10:21         ` C.H. Zhao
  2016-10-03 17:22           ` Scott Wood
  0 siblings, 1 reply; 11+ messages in thread
From: C.H. Zhao @ 2016-09-29 10:21 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, z.chenhui, Jason Jin



From: Scott Wood <oss@buserror.net>
Sent: Thursday, September 29, 2016 4:03 AM
To: C.H. Zhao
Cc: linuxppc-dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; z.chenhui@gmail.com; Jason Jin
Subject: Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
    
On Tue, 2016-09-27 at 11:05 +0000, C.H. Zhao wrote:
> From: Scott Wood <oss@buserror.net>
> Sent: Sunday, September 25, 2016 3:24 PM
> To: C.H. Zhao
> Cc: linuxppc-dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; z.chenhui@g
> mail.com; Jason Jin
> Subject: Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
>     
> On Tue, Aug 02, 2016 at 07:59:31PM +0800, Chenhui Zhao wrote:
> > 
> > T104x has deep sleep feature, which can switch off most parts of
> > the SoC when it is in deep sleep mode. This way, it becomes more
> > energy-efficient.
> > 
> > The DDR controller will also be powered off in deep sleep. Therefore,
> > the last stage (the latter part of fsl_dp_enter_low) will run without DDR
> > access. This piece of code and related TLBs are prefetched in advance.
> > 
> > Due to the different initialization code between 32-bit and 64-bit, they
> > have separate resume entry and precedure.
> > 
> > The feature supports 32-bit and 64-bit kernel mode.
> > 
> > Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> > ---
> >   arch/powerpc/include/asm/fsl_pm.h             |  24 ++
> >   arch/powerpc/kernel/asm-offsets.c             |  12 +
> >   arch/powerpc/kernel/fsl_booke_entry_mapping.S |  10 +
> >   arch/powerpc/kernel/head_64.S                 |   2 +-
> >   arch/powerpc/platforms/85xx/Makefile          |   1 +
> >   arch/powerpc/platforms/85xx/deepsleep.c       | 278 ++++++++++++++
> >   arch/powerpc/platforms/85xx/qoriq_pm.c        |  25 ++
> >   arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531
> > ++++++++++++++++++++++++++
> >   arch/powerpc/sysdev/fsl_rcpm.c                |   8 +-
> >   9 files changed, 889 insertions(+), 2 deletions(-)
> >   create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> >   create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S
> > 
> > diff --git a/arch/powerpc/include/asm/fsl_pm.h
> > b/arch/powerpc/include/asm/fsl_pm.h
> > index e05049b..48c2631 100644
> > --- a/arch/powerpc/include/asm/fsl_pm.h
> > +++ b/arch/powerpc/include/asm/fsl_pm.h
> > @@ -20,6 +20,7 @@
> >   
> >   #define PLAT_PM_SLEEP        20
> >   #define PLAT_PM_LPM20        30
> > +#define PLAT_PM_LPM35        40
> >   
> >   #define FSL_PM_SLEEP         (1 << 0)
> >   #define FSL_PM_DEEP_SLEEP    (1 << 1)
> > @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
> >   
> >   int __init fsl_rcpm_init(void);
> >   
> > +#ifdef CONFIG_FSL_QORIQ_PM
> > +int fsl_enter_deepsleep(void);
> > +int fsl_deepsleep_init(void);
> > +#else
> > +static inline int fsl_enter_deepsleep(void) { return -1; }
> > +static inline int fsl_deepsleep_init(void) { return -1; }
> > +#endif
> Please return proper error codes.
> 
> Where can fsl_deepsleep_init() be called without CONFIG_FSL_QORIQ_PM?
> 
> [Chenhui] I can get rid of the ifdef here. And add it
> in arch/powerpc/sysdev/fsl_rcpm.c.

No, this is the right place for the ifdef for functions that are called from
code that doesn't depend on CONFIG_FSL_QORIQ_PM.  But fsl_deepsleep_init() is
called from deepsleep.c which is only built with CONFIG_FSL_QORIQ_PM, and it's
hard to picture a scenario where it would be called from elsewhere.


[Chenhui] You are right. No need to enclose fsl_deepsleep_init() in the ifdef.
                 But regarding fsl_enter_deepsleep(), it is called in rcpm_v2_plat_enter_sleep()
                 in arch/powerpc/sysdev/fsl_rcpm.c. It still needs to be enclosed in the ifdef.
                 I would change it like:

int fsl_deepsleep_init(void);                                              
#ifdef CONFIG_FSL_QORIQ_PM                                                 
int fsl_enter_deepsleep(void);
#else           
static inline int fsl_enter_deepsleep(void) { return -EINVAL; }            
#endif


> > diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > index 83dd0f6..659b059 100644
> > --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
> > @@ -173,6 +173,10 @@ skpinv:  addi    r6,r6,1                         /*
> > Increment */
> >         lis     r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h
> >         ori     r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M,
> > M_IF_NEEDED)@l
> >         mtspr   SPRN_MAS2,r6
> > +#ifdef ENTRY_DEEPSLEEP_SETUP
> > +     LOAD_REG_IMMEDIATE(r8, MEMORY_START)
> > +     ori     r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR)
> > +#endif
> >         mtspr   SPRN_MAS3,r8
> >         tlbwe
> >   
> Have you tried this with a relocatable kernel?
> 
> [Chenhui] Not yet. Not sure whether it has been supported on QorIQ platform.

It is supported, and deep sleep needs to work with it.


[Chenhui] OK. I'm going to work something out.

> > +static void fsl_dp_set_resume_pointer(void)
> > +{
> > +     u32 resume_addr;
> > +
> > +     /* the bootloader will finally jump to this address to return kernel
> > */
> > +#ifdef CONFIG_PPC32
> > +     resume_addr = (u32)(__pa(fsl_booke_deep_sleep_resume));
> > +#else
> > +     resume_addr = (u32)(__pa(*(u64 *)fsl_booke_deep_sleep_resume)
> > +                         & 0xffffffff);
> > +#endif
> Why are you masking the physical address by 0xffffffff?  Besides the
> (u32) cast accomplishing the same thing, wouldn't it be a problem if
> (e.g. due to a relocatable kernel) the address is above 4 GiB?
> 
> [Chenhui] Here, I assumed kernel is below 4 GiB. Maybe I should add a
> comment here.

It needs a fix rather than a comment, unless you can show that the relocatable
mechanism doesn't support kernels over 4 GiB (I don't remember of the top of
my head whether it does).

-Scott

[Chenhui] OK. I'm going to work something out.
    

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

* Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
  2016-09-29 10:21         ` C.H. Zhao
@ 2016-10-03 17:22           ` Scott Wood
  0 siblings, 0 replies; 11+ messages in thread
From: Scott Wood @ 2016-10-03 17:22 UTC (permalink / raw)
  To: C.H. Zhao; +Cc: linuxppc-dev, linux-kernel, z.chenhui, Jason Jin

On Thu, 2016-09-29 at 10:21 +0000, C.H. Zhao wrote:
> 
> From: Scott Wood <oss@buserror.net>
> Sent: Thursday, September 29, 2016 4:03 AM
> To: C.H. Zhao
> Cc: linuxppc-dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; z.chenhui@g
> mail.com; Jason Jin
> Subject: Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
>     
> On Tue, 2016-09-27 at 11:05 +0000, C.H. Zhao wrote:
> > 
> > From: Scott Wood <oss@buserror.net>
> > Sent: Sunday, September 25, 2016 3:24 PM
> > To: C.H. Zhao
> > Cc: linuxppc-dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; z.chenhui
> > @g
> > mail.com; Jason Jin
> > Subject: Re: [v3,4/5] powerpc/pm: support deep sleep feature on T104x
> >     
> > On Tue, Aug 02, 2016 at 07:59:31PM +0800, Chenhui Zhao wrote:
> > > 
> > > 
> > > T104x has deep sleep feature, which can switch off most parts of
> > > the SoC when it is in deep sleep mode. This way, it becomes more
> > > energy-efficient.
> > > 
> > > The DDR controller will also be powered off in deep sleep. Therefore,
> > > the last stage (the latter part of fsl_dp_enter_low) will run without
> > > DDR
> > > access. This piece of code and related TLBs are prefetched in advance.
> > > 
> > > Due to the different initialization code between 32-bit and 64-bit, they
> > > have separate resume entry and precedure.
> > > 
> > > The feature supports 32-bit and 64-bit kernel mode.
> > > 
> > > Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> > > ---
> > >   arch/powerpc/include/asm/fsl_pm.h             |  24 ++
> > >   arch/powerpc/kernel/asm-offsets.c             |  12 +
> > >   arch/powerpc/kernel/fsl_booke_entry_mapping.S |  10 +
> > >   arch/powerpc/kernel/head_64.S                 |   2 +-
> > >   arch/powerpc/platforms/85xx/Makefile          |   1 +
> > >   arch/powerpc/platforms/85xx/deepsleep.c       | 278 ++++++++++++++
> > >   arch/powerpc/platforms/85xx/qoriq_pm.c        |  25 ++
> > >   arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531
> > > ++++++++++++++++++++++++++
> > >   arch/powerpc/sysdev/fsl_rcpm.c                |   8 +-
> > >   9 files changed, 889 insertions(+), 2 deletions(-)
> > >   create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> > >   create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S
> > > 
> > > diff --git a/arch/powerpc/include/asm/fsl_pm.h
> > > b/arch/powerpc/include/asm/fsl_pm.h
> > > index e05049b..48c2631 100644
> > > --- a/arch/powerpc/include/asm/fsl_pm.h
> > > +++ b/arch/powerpc/include/asm/fsl_pm.h
> > > @@ -20,6 +20,7 @@
> > >   
> > >   #define PLAT_PM_SLEEP        20
> > >   #define PLAT_PM_LPM20        30
> > > +#define PLAT_PM_LPM35        40
> > >   
> > >   #define FSL_PM_SLEEP         (1 << 0)
> > >   #define FSL_PM_DEEP_SLEEP    (1 << 1)
> > > @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
> > >   
> > >   int __init fsl_rcpm_init(void);
> > >   
> > > +#ifdef CONFIG_FSL_QORIQ_PM
> > > +int fsl_enter_deepsleep(void);
> > > +int fsl_deepsleep_init(void);
> > > +#else
> > > +static inline int fsl_enter_deepsleep(void) { return -1; }
> > > +static inline int fsl_deepsleep_init(void) { return -1; }
> > > +#endif
> > Please return proper error codes.
> > 
> > Where can fsl_deepsleep_init() be called without CONFIG_FSL_QORIQ_PM?
> > 
> > [Chenhui] I can get rid of the ifdef here. And add it
> > in arch/powerpc/sysdev/fsl_rcpm.c.
> No, this is the right place for the ifdef for functions that are called from
> code that doesn't depend on CONFIG_FSL_QORIQ_PM.  But fsl_deepsleep_init()
> is
> called from deepsleep.c which is only built with CONFIG_FSL_QORIQ_PM, and
> it's
> hard to picture a scenario where it would be called from elsewhere.
> 
> 
> [Chenhui] You are right. No need to enclose fsl_deepsleep_init() in the
> ifdef.
>                  But regarding fsl_enter_deepsleep(), it is called in
> rcpm_v2_plat_enter_sleep()
>                  in arch/powerpc/sysdev/fsl_rcpm.c. It still needs to be
> enclosed in the ifdef.

Right.  That's why I specifically asked about fsl_deepsleep_init(). :-)

-Scott

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

end of thread, other threads:[~2016-10-03 17:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-02 11:59 [PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature Chenhui Zhao
2016-08-02 11:59 ` [PATCH v3 0/5] powerpc/pm: QorIQ deep sleep Chenhui Zhao
2016-08-02 11:59 ` [PATCH v3 2/5] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM Chenhui Zhao
2016-08-02 11:59 ` [PATCH v3 3/5] powerpc: pm: add EPU FSM configuration for deep sleep Chenhui Zhao
2016-08-02 11:59 ` [PATCH v3 4/5] powerpc/pm: support deep sleep feature on T104x Chenhui Zhao
2016-09-25  7:24   ` [v3,4/5] " Scott Wood
2016-09-27 11:05     ` C.H. Zhao
2016-09-28 20:03       ` Scott Wood
2016-09-29 10:21         ` C.H. Zhao
2016-10-03 17:22           ` Scott Wood
2016-08-02 11:59 ` [PATCH v3 5/5] powerpc/pm: save and restore registers during deep sleep Chenhui Zhao

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