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