[PATCH 7/9] fsl: add EPU FSM configuration for deep sleep

From: Chenhui Zhao
Date: Thu Mar 06 2014 - 23:59:43 EST


From: Hongbo Zhang <hongbo.zhang@xxxxxxxxxxxxx>

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: Hongbo Zhang <hongbo.zhang@xxxxxxxxxxxxx>
Signed-off-by: Chenhui Zhao <chenhui.zhao@xxxxxxxxxxxxx>
---
arch/powerpc/platforms/85xx/Kconfig | 1 +
arch/powerpc/sysdev/fsl_soc.h | 3 +
drivers/platform/Kconfig | 4 +
drivers/platform/Makefile | 1 +
drivers/platform/fsl/Kconfig | 10 +
drivers/platform/fsl/Makefile | 5 +
drivers/platform/fsl/sleep_fsm.c | 415 +++++++++++++++++++++++++++++++++++
7 files changed, 439 insertions(+), 0 deletions(-)
create mode 100644 drivers/platform/fsl/Kconfig
create mode 100644 drivers/platform/fsl/Makefile
create mode 100644 drivers/platform/fsl/sleep_fsm.c

diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 54d8843..27e2174 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -261,6 +261,7 @@ config CORENET_GENERIC
select GPIO_MPC8XXX
select HAS_RAPIDIO
select PPC_EPAPR_HV_PIC
+ select FSL_SLEEP_FSM if SUSPEND
help
This option enables support for the FSL CoreNet based boards.
For 32bit kernel, the following boards are supported:
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 9b9a34a..eb83a30 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -69,5 +69,8 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;

extern int fsl_rcpm_init(void);

+extern void fsl_dp_fsm_setup(void *dcsr_base);
+extern void fsl_dp_fsm_clean(void *dcsr_base);
+
#endif
#endif
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 09fde58..6539e6d 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -6,3 +6,7 @@ source "drivers/platform/goldfish/Kconfig"
endif

source "drivers/platform/chrome/Kconfig"
+
+if FSL_SOC
+source "drivers/platform/fsl/Kconfig"
+endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 3656b7b..37c6f72 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_OLPC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
+obj-$(CONFIG_FSL_SOC) += fsl/
diff --git a/drivers/platform/fsl/Kconfig b/drivers/platform/fsl/Kconfig
new file mode 100644
index 0000000..72ed053
--- /dev/null
+++ b/drivers/platform/fsl/Kconfig
@@ -0,0 +1,10 @@
+#
+# Freescale Specific Power Management Drivers
+#
+
+config FSL_SLEEP_FSM
+ bool
+ help
+ This driver configures a hardware FSM (Finite State Machine) for deep sleep.
+ The FSM is used to finish clean-ups at the last stage of system entering deep
+ sleep, and also wakes up system when a wake up event happens.
diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefile
new file mode 100644
index 0000000..d99ca0e
--- /dev/null
+++ b/drivers/platform/fsl/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for linux/drivers/platform/fsl
+# Freescale Specific Power Management Drivers
+#
+obj-$(CONFIG_FSL_SLEEP_FSM) += sleep_fsm.o
diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/sleep_fsm.c
new file mode 100644
index 0000000..1033332
--- /dev/null
+++ b/drivers/platform/fsl/sleep_fsm.c
@@ -0,0 +1,415 @@
+/*
+ * Freescale deep sleep FSM (finite-state machine) configuration
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * Author: Hongbo Zhang <hongbo.zhang@xxxxxxxxxxxxx>
+ * Chenhui Zhao <chenhui.zhao@xxxxxxxxxxxxx>
+ *
+ * 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/io.h>
+#include <linux/types.h>
+
+#define FSL_STRIDE_4B 4
+#define FSL_STRIDE_8B 8
+
+/* Event Processor Global Control Register */
+#define EPGCR 0x000
+
+/* Event Processor EVT Pin Control Registers */
+#define EPEVTCR0 0x050
+#define EPEVTCR1 0x054
+#define EPEVTCR2 0x058
+#define EPEVTCR3 0x05C
+#define EPEVTCR4 0x060
+#define EPEVTCR5 0x064
+#define EPEVTCR6 0x068
+#define EPEVTCR7 0x06C
+#define EPEVTCR8 0x070
+#define EPEVTCR9 0x074
+
+/* Event Processor Crosstrigger Control Register */
+#define EPXTRIGCR 0x090
+
+/* Event Processor Input Mux Control Registers */
+#define EPIMCR0 0x100
+#define EPIMCR1 0x104
+#define EPIMCR2 0x108
+#define EPIMCR3 0x10C
+#define EPIMCR4 0x110
+#define EPIMCR5 0x114
+#define EPIMCR6 0x118
+#define EPIMCR7 0x11C
+#define EPIMCR8 0x120
+#define EPIMCR9 0x124
+#define EPIMCR10 0x128
+#define EPIMCR11 0x12C
+#define EPIMCR12 0x130
+#define EPIMCR13 0x134
+#define EPIMCR14 0x138
+#define EPIMCR15 0x13C
+#define EPIMCR16 0x140
+#define EPIMCR17 0x144
+#define EPIMCR18 0x148
+#define EPIMCR19 0x14C
+#define EPIMCR20 0x150
+#define EPIMCR21 0x154
+#define EPIMCR22 0x158
+#define EPIMCR23 0x15C
+#define EPIMCR24 0x160
+#define EPIMCR25 0x164
+#define EPIMCR26 0x168
+#define EPIMCR27 0x16C
+#define EPIMCR28 0x170
+#define EPIMCR29 0x174
+#define EPIMCR30 0x178
+#define EPIMCR31 0x17C
+
+/* Event Processor SCU Mux Control Registers */
+#define EPSMCR0 0x200
+#define EPSMCR1 0x208
+#define EPSMCR2 0x210
+#define EPSMCR3 0x218
+#define EPSMCR4 0x220
+#define EPSMCR5 0x228
+#define EPSMCR6 0x230
+#define EPSMCR7 0x238
+#define EPSMCR8 0x240
+#define EPSMCR9 0x248
+#define EPSMCR10 0x250
+#define EPSMCR11 0x258
+#define EPSMCR12 0x260
+#define EPSMCR13 0x268
+#define EPSMCR14 0x270
+#define EPSMCR15 0x278
+
+/* Event Processor Event Control Registers */
+#define EPECR0 0x300
+#define EPECR1 0x304
+#define EPECR2 0x308
+#define EPECR3 0x30C
+#define EPECR4 0x310
+#define EPECR5 0x314
+#define EPECR6 0x318
+#define EPECR7 0x31C
+#define EPECR8 0x320
+#define EPECR9 0x324
+#define EPECR10 0x328
+#define EPECR11 0x32C
+#define EPECR12 0x330
+#define EPECR13 0x334
+#define EPECR14 0x338
+#define EPECR15 0x33C
+
+/* Event Processor Action Control Registers */
+#define EPACR0 0x400
+#define EPACR1 0x404
+#define EPACR2 0x408
+#define EPACR3 0x40C
+#define EPACR4 0x410
+#define EPACR5 0x414
+#define EPACR6 0x418
+#define EPACR7 0x41C
+#define EPACR8 0x420
+#define EPACR9 0x424
+#define EPACR10 0x428
+#define EPACR11 0x42C
+#define EPACR12 0x430
+#define EPACR13 0x434
+#define EPACR14 0x438
+#define EPACR15 0x43C
+
+/* Event Processor Counter Control Registers */
+#define EPCCR0 0x800
+#define EPCCR1 0x804
+#define EPCCR2 0x808
+#define EPCCR3 0x80C
+#define EPCCR4 0x810
+#define EPCCR5 0x814
+#define EPCCR6 0x818
+#define EPCCR7 0x81C
+#define EPCCR8 0x820
+#define EPCCR9 0x824
+#define EPCCR10 0x828
+#define EPCCR11 0x82C
+#define EPCCR12 0x830
+#define EPCCR13 0x834
+#define EPCCR14 0x838
+#define EPCCR15 0x83C
+
+/* Event Processor Counter Compare Registers */
+#define EPCMPR0 0x900
+#define EPCMPR1 0x904
+#define EPCMPR2 0x908
+#define EPCMPR3 0x90C
+#define EPCMPR4 0x910
+#define EPCMPR5 0x914
+#define EPCMPR6 0x918
+#define EPCMPR7 0x91C
+#define EPCMPR8 0x920
+#define EPCMPR9 0x924
+#define EPCMPR10 0x928
+#define EPCMPR11 0x92C
+#define EPCMPR12 0x930
+#define EPCMPR13 0x934
+#define EPCMPR14 0x938
+#define EPCMPR15 0x93C
+
+/* Event Processor Counter Register */
+#define EPCTR0 0xA00
+#define EPCTR1 0xA04
+#define EPCTR2 0xA08
+#define EPCTR3 0xA0C
+#define EPCTR4 0xA10
+#define EPCTR5 0xA14
+#define EPCTR6 0xA18
+#define EPCTR7 0xA1C
+#define EPCTR8 0xA20
+#define EPCTR9 0xA24
+#define EPCTR10 0xA28
+#define EPCTR11 0xA2C
+#define EPCTR12 0xA30
+#define EPCTR13 0xA34
+#define EPCTR14 0xA38
+#define EPCTR15 0xA3C
+#define EPCTR16 0xA40
+#define EPCTR17 0xA44
+#define EPCTR18 0xA48
+#define EPCTR19 0xA4C
+#define EPCTR20 0xA50
+#define EPCTR21 0xA54
+#define EPCTR22 0xA58
+#define EPCTR23 0xA5C
+#define EPCTR24 0xA60
+#define EPCTR25 0xA64
+#define EPCTR26 0xA68
+#define EPCTR27 0xA6C
+#define EPCTR28 0xA70
+#define EPCTR29 0xA74
+#define EPCTR30 0xA78
+#define EPCTR31 0xA7C
+
+/* 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
+
+/* Block offsets */
+#define RCPM_BLOCK_OFFSET 0x00022000
+#define EPU_BLOCK_OFFSET 0x00000000
+#define NPC_BLOCK_OFFSET 0x00001000
+
+static void *g_dcsr_base;
+
+static inline void rcpm_write(u32 offset, u32 val)
+{
+ out_be32(g_dcsr_base + RCPM_BLOCK_OFFSET + offset, val);
+}
+
+static inline void epu_write(u32 offset, u32 val)
+{
+ out_be32(g_dcsr_base + EPU_BLOCK_OFFSET + offset, val);
+}
+
+static inline void npc_write(u32 offset, u32 val)
+{
+ out_be32(g_dcsr_base + NPC_BLOCK_OFFSET + offset, val);
+}
+
+/**
+ * fsl_dp_fsm_setup - Configure EPU's FSM
+ * @dcsr_base: the base address of DCSR registers
+ */
+void fsl_dp_fsm_setup(void *dcsr_base)
+{
+ u32 offset;
+
+ /*
+ * Globle static variable is safe here, becsuse this function is only
+ * called once at the last stage of suspend, when there is only one CPU
+ * running and task switching is also disabled.
+ */
+ g_dcsr_base = dcsr_base;
+
+ /* Disable All SCU Actions */
+ for (offset = EPACR0; offset <= EPACR15; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPEVTCRn */
+ for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear Event Processor Global Control Register */
+ epu_write(EPGCR, 0);
+
+ /* Clear EPSMCRn */
+ for (offset = EPSMCR0; offset <= EPSMCR15; offset += FSL_STRIDE_8B)
+ epu_write(offset, 0);
+
+ /* Clear EPCCRn */
+ for (offset = EPCCR0; offset <= EPCCR15; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPCMPRn */
+ for (offset = EPCMPR0; offset <= EPCMPR15; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /*
+ * Clear EPCTRn
+ * Warm Device Reset does NOT reset these counter, so clear them
+ * explicitly. Or, the second time entering deep sleep will fail.
+ */
+ for (offset = EPCTR0; offset <= EPCTR31; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPIMCRn */
+ for (offset = EPIMCR0; offset <= EPIMCR31; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPXTRIGCRn */
+ epu_write(EPXTRIGCR, 0);
+
+ /* Disable all SCUs EPECRn */
+ for (offset = EPECR0; offset <= EPECR15; offset += FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Set up the SCU chaining */
+ epu_write(EPECR15, 0x00000004);
+ epu_write(EPECR14, 0x02000084);
+ epu_write(EPECR13, 0x08000084);
+ epu_write(EPECR12, 0x80000084);
+ epu_write(EPECR11, 0x90000084);
+ epu_write(EPECR10, 0x42000084);
+ epu_write(EPECR9, 0x08000084);
+ epu_write(EPECR8, 0x60000084);
+ epu_write(EPECR7, 0x80000084);
+ epu_write(EPECR6, 0x80000084);
+ epu_write(EPECR5, 0x08000004);
+ epu_write(EPECR4, 0x20000084);
+ epu_write(EPECR3, 0x80000084);
+ epu_write(EPECR2, 0xF0004004);
+
+ /* EVT Pin Configuration. SCU8 triger EVT2, and SCU11 triger EVT9 */
+ epu_write(EPEVTCR2, 0x80000001);
+ epu_write(EPEVTCR9, 0xB0000001);
+
+ /* Configure the EPU Counter Values */
+ epu_write(EPCMPR15, 0x000000FF);
+ epu_write(EPCMPR14, 0x000000FF);
+ epu_write(EPCMPR12, 0x000000FF);
+ epu_write(EPCMPR11, 0x000000FF);
+ epu_write(EPCMPR10, 0x000000FF);
+ epu_write(EPCMPR9, 0x000000FF);
+ epu_write(EPCMPR8, 0x000000FF);
+ epu_write(EPCMPR5, 0x00000020);
+ epu_write(EPCMPR4, 0x000000FF);
+ epu_write(EPCMPR2, 0x000000FF);
+
+ /* Configure the EPU Counters */
+ epu_write(EPCCR15, 0x92840000);
+ epu_write(EPCCR14, 0x92840000);
+ epu_write(EPCCR12, 0x92840000);
+ epu_write(EPCCR11, 0x92840000);
+ epu_write(EPCCR10, 0x92840000);
+ epu_write(EPCCR9, 0x92840000);
+ epu_write(EPCCR8, 0x92840000);
+ epu_write(EPCCR5, 0x92840000);
+ epu_write(EPCCR4, 0x92840000);
+ epu_write(EPCCR2, 0x92840000);
+
+ /* Configure the SCUs Inputs */
+ epu_write(EPSMCR15, 0x76000000);
+ epu_write(EPSMCR14, 0x00000031);
+ epu_write(EPSMCR13, 0x00003100);
+ epu_write(EPSMCR12, 0x7F000000);
+ epu_write(EPSMCR11, 0x31740000);
+ epu_write(EPSMCR10, 0x65000030);
+ epu_write(EPSMCR9, 0x00003000);
+ epu_write(EPSMCR8, 0x64300000);
+ epu_write(EPSMCR7, 0x30000000);
+ epu_write(EPSMCR6, 0x7C000000);
+ epu_write(EPSMCR5, 0x00002E00);
+ epu_write(EPSMCR4, 0x002F0000);
+ epu_write(EPSMCR3, 0x2F000000);
+ epu_write(EPSMCR2, 0x6C700000);
+
+ /* Configure the SCUs Actions */
+ epu_write(EPACR15, 0x02000000);
+ epu_write(EPACR14, 0x04000000);
+ epu_write(EPACR13, 0x06000000);
+ epu_write(EPACR12, 0x00000003);
+ epu_write(EPACR10, 0x00000020);
+ epu_write(EPACR9, 0x0000001C);
+ epu_write(EPACR5, 0x00000040);
+ epu_write(EPACR3, 0x00000080);
+
+ /* Configure the SCUs and Timers Mux */
+ epu_write(EPIMCR31, 0x76000000);
+ epu_write(EPIMCR28, 0x76000000);
+ epu_write(EPIMCR22, 0x6C000000);
+ epu_write(EPIMCR20, 0x48000000);
+ epu_write(EPIMCR16, 0x6A000000);
+ epu_write(EPIMCR12, 0x44000000);
+ epu_write(EPIMCR5, 0x40000000);
+ epu_write(EPIMCR4, 0x44000000);
+
+ /* Configure pulse or level triggers */
+ epu_write(EPXTRIGCR, 0x0000FFDF);
+
+ /* Configure the NPC tMMA registers*/
+ npc_write(NCR, 0x80000000);
+ npc_write(MCCR1, 0);
+ npc_write(MCSR1, 0);
+ npc_write(MMAR1LO, 0);
+ npc_write(MMAR1HI, 0);
+ npc_write(MMDR1, 0);
+ npc_write(MCSR2, 0);
+ npc_write(MMAR2LO, 0);
+ npc_write(MMAR2HI, 0);
+ npc_write(MMDR2, 0);
+ npc_write(MCSR3, 0x80000000);
+ npc_write(MMAR3LO, 0x000E2130);
+ npc_write(MMAR3HI, 0x00030000);
+ npc_write(MMDR3, 0x00020000);
+
+ /* Configure RCPM for detecting Core0âs PH15 state */
+ rcpm_write(CSTTACR0, 0x00001001);
+ rcpm_write(CG1CR0, 0x00000001);
+
+}
+
+void fsl_dp_fsm_clean(void *dcsr_base)
+{
+
+ epu_write(EPEVTCR2, 0);
+ epu_write(EPEVTCR9, 0);
+
+ epu_write(EPGCR, 0);
+ epu_write(EPECR15, 0);
+
+ rcpm_write(CSTTACR0, 0);
+ rcpm_write(CG1CR0, 0);
+
+}
--
1.7.3


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/