* [PATCH 2/9] powerpc/cache: add cache flush operation for various e500
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
@ 2014-03-07 4:57 ` Chenhui Zhao
2014-03-07 4:57 ` [PATCH 3/9] powerpc/rcpm: add RCPM driver Chenhui Zhao
` (6 subsequent siblings)
7 siblings, 0 replies; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:57 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
Various e500 core have different cache architecture, so they
need different cache flush operations. Therefore, add a callback
function cpu_flush_caches to the struct cpu_spec. The cache flush
operation for the specific kind of e500 is selected at init time.
The callback function will flush all caches in the current cpu.
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
arch/powerpc/include/asm/cacheflush.h | 2 -
arch/powerpc/include/asm/cputable.h | 11 +++
arch/powerpc/kernel/asm-offsets.c | 3 +
arch/powerpc/kernel/cpu_setup_fsl_booke.S | 114 ++++++++++++++++++++++++++++-
arch/powerpc/kernel/cputable.c | 4 +
arch/powerpc/kernel/head_fsl_booke.S | 74 -------------------
arch/powerpc/platforms/85xx/smp.c | 4 +-
7 files changed, 134 insertions(+), 78 deletions(-)
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index 5b93122..039753e 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,8 +30,6 @@ extern void flush_dcache_page(struct page *page);
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-extern void __flush_disable_L1(void);
-
extern void flush_icache_range(unsigned long, unsigned long);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 617cc76..2c497a2 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -43,6 +43,13 @@ extern int machine_check_e500(struct pt_regs *regs);
extern int machine_check_e200(struct pt_regs *regs);
extern int machine_check_47x(struct pt_regs *regs);
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+extern void __flush_caches_e500v2(void);
+extern void __flush_caches_e500mc(void);
+extern void __flush_caches_e5500(void);
+extern void __flush_caches_e6500(void);
+#endif
+
/* NOTE WELL: Update identify_cpu() if fields are added or removed! */
struct cpu_spec {
/* CPU is matched via (PVR & pvr_mask) == pvr_value */
@@ -59,6 +66,10 @@ struct cpu_spec {
unsigned int icache_bsize;
unsigned int dcache_bsize;
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+ /* flush caches of the cpu which is running the function */
+ void (*cpu_flush_caches)(void);
+#endif
/* number of performance monitor counters */
unsigned int num_pmcs;
enum powerpc_pmc_type pmc_type;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8d1d94d..5157fb4 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -372,6 +372,9 @@ int main(void)
DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
+#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC)
+ DEFINE(CPU_FLUSH_CACHES, offsetof(struct cpu_spec, cpu_flush_caches));
+#endif
DEFINE(pbe_address, offsetof(struct pbe, address));
DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index cc2d896..e59d6de 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -1,7 +1,7 @@
/*
* This file contains low level CPU setup functions.
* Kumar Gala <galak@kernel.crashing.org>
- * Copyright 2009 Freescale Semiconductor, Inc.
+ * Copyright 2009, 2014 Freescale Semiconductor, Inc.
*
* Based on cpu_setup_6xx code by
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
@@ -13,11 +13,13 @@
*
*/
+#include <asm/page.h>
#include <asm/processor.h>
#include <asm/cputable.h>
#include <asm/ppc_asm.h>
#include <asm/mmu-book3e.h>
#include <asm/asm-offsets.h>
+#include <asm/mpc85xx.h>
_GLOBAL(__e500_icache_setup)
mfspr r0, SPRN_L1CSR1
@@ -223,3 +225,113 @@ _GLOBAL(__setup_cpu_e5500)
mtlr r5
blr
#endif
+
+/* flush L1 date cache, it can apply to e500v2, e500mc and e5500 */
+_GLOBAL(flush_dcache_L1)
+ mfmsr r10
+ wrteei 0
+
+ mfspr r3,SPRN_L1CFG0
+ rlwinm r5,r3,9,3 /* Extract cache block size */
+ twlgti r5,1 /* Only 32 and 64 byte cache blocks
+ * are currently defined.
+ */
+ li r4,32
+ subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
+ * log2(number of ways)
+ */
+ slw r5,r4,r5 /* r5 = cache block size */
+
+ rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
+ mulli r7,r7,13 /* An 8-way cache will require 13
+ * loads per set.
+ */
+ slw r7,r7,r6
+
+ /* save off HID0 and set DCFA */
+ mfspr r8,SPRN_HID0
+ ori r9,r8,HID0_DCFA@l
+ mtspr SPRN_HID0,r9
+ isync
+
+ LOAD_REG_IMMEDIATE(r6, KERNELBASE)
+ mr r4, r6
+ mtctr r7
+
+1: lwz r3,0(r4) /* Load... */
+ add r4,r4,r5
+ bdnz 1b
+
+ msync
+ mr r4, r6
+ mtctr r7
+
+1: dcbf 0,r4 /* ...and flush. */
+ add r4,r4,r5
+ bdnz 1b
+
+ /* restore HID0 */
+ mtspr SPRN_HID0,r8
+ isync
+
+ wrtee r10
+
+ blr
+
+has_L2_cache:
+ /* skip L2 cache on P2040/P2040E as they have no L2 cache */
+ mfspr r3, SPRN_SVR
+ /* shift right by 8 bits and clear E bit of SVR */
+ rlwinm r4, r3, 24, ~0x800
+
+ lis r3, SVR_P2040@h
+ ori r3, r3, SVR_P2040@l
+ cmpw r4, r3
+ beq 1f
+
+ li r3, 1
+ blr
+1:
+ li r3, 0
+ blr
+
+/* flush backside L2 cache */
+flush_backside_L2_cache:
+ mflr r10
+ bl has_L2_cache
+ mtlr r10
+ cmpwi r3, 0
+ beq 2f
+
+ /* Flush the L2 cache */
+ mfspr r3, SPRN_L2CSR0
+ ori r3, r3, L2CSR0_L2FL@l
+ msync
+ isync
+ mtspr SPRN_L2CSR0,r3
+ isync
+
+ /* check if it is complete */
+1: mfspr r3,SPRN_L2CSR0
+ andi. r3, r3, L2CSR0_L2FL@l
+ bne 1b
+2:
+ blr
+
+_GLOBAL(__flush_caches_e500v2)
+ mflr r0
+ bl flush_dcache_L1
+ mtlr r0
+ blr
+
+_GLOBAL(__flush_caches_e500mc)
+_GLOBAL(__flush_caches_e5500)
+ mflr r0
+ bl flush_dcache_L1
+ bl flush_backside_L2_cache
+ mtlr r0
+ blr
+
+/* L1 Data Cache of e6500 contains no modified data, no flush is required */
+_GLOBAL(__flush_caches_e6500)
+ blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 6c8dd5d..8e70aa7 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -2068,6 +2068,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_e500v2,
.machine_check = machine_check_e500,
.platform = "ppc8548",
+ .cpu_flush_caches = __flush_caches_e500v2,
},
{ /* e500mc */
.pvr_mask = 0xffff0000,
@@ -2086,6 +2087,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_e500mc,
.machine_check = machine_check_e500mc,
.platform = "ppce500mc",
+ .cpu_flush_caches = __flush_caches_e500mc,
},
#endif /* CONFIG_PPC32 */
{ /* e5500 */
@@ -2108,6 +2110,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
#endif
.machine_check = machine_check_e500mc,
.platform = "ppce5500",
+ .cpu_flush_caches = __flush_caches_e5500,
},
{ /* e6500 */
.pvr_mask = 0xffff0000,
@@ -2130,6 +2133,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
#endif
.machine_check = machine_check_e500mc,
.platform = "ppce6500",
+ .cpu_flush_caches = __flush_caches_e6500,
},
#ifdef CONFIG_PPC32
{ /* default match */
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index b497188..20204fe 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -1067,80 +1067,6 @@ _GLOBAL(set_context)
isync /* Force context change */
blr
-_GLOBAL(flush_dcache_L1)
- mfspr r3,SPRN_L1CFG0
-
- rlwinm r5,r3,9,3 /* Extract cache block size */
- twlgti r5,1 /* Only 32 and 64 byte cache blocks
- * are currently defined.
- */
- li r4,32
- subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
- * log2(number of ways)
- */
- slw r5,r4,r5 /* r5 = cache block size */
-
- rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
- mulli r7,r7,13 /* An 8-way cache will require 13
- * loads per set.
- */
- slw r7,r7,r6
-
- /* save off HID0 and set DCFA */
- mfspr r8,SPRN_HID0
- ori r9,r8,HID0_DCFA@l
- mtspr SPRN_HID0,r9
- isync
-
- lis r4,KERNELBASE@h
- mtctr r7
-
-1: lwz r3,0(r4) /* Load... */
- add r4,r4,r5
- bdnz 1b
-
- msync
- lis r4,KERNELBASE@h
- mtctr r7
-
-1: dcbf 0,r4 /* ...and flush. */
- add r4,r4,r5
- bdnz 1b
-
- /* restore HID0 */
- mtspr SPRN_HID0,r8
- isync
-
- blr
-
-/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
-_GLOBAL(__flush_disable_L1)
- mflr r10
- bl flush_dcache_L1 /* Flush L1 d-cache */
- mtlr r10
-
- mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
- li r5, 2
- rlwimi r4, r5, 0, 3
-
- msync
- isync
- mtspr SPRN_L1CSR0, r4
- isync
-
-1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
- andi. r4, r4, 2
- bne 1b
-
- mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
- li r5, 2
- rlwimi r4, r5, 0, 3
-
- mtspr SPRN_L1CSR1, r4
- isync
-
- blr
-
#ifdef CONFIG_SMP
/* When we get here, r24 needs to hold the CPU # */
.globl __secondary_start
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 6382098..2e5911e 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -137,7 +137,9 @@ static void smp_85xx_mach_cpu_die(void)
mtspr(SPRN_TCR, 0);
- __flush_disable_L1();
+ if (cur_cpu_spec && cur_cpu_spec->cpu_flush_caches)
+ cur_cpu_spec->cpu_flush_caches();
+
tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
mtspr(SPRN_HID0, tmp);
isync();
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH 3/9] powerpc/rcpm: add RCPM driver
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
2014-03-07 4:57 ` [PATCH 2/9] powerpc/cache: add cache flush operation for various e500 Chenhui Zhao
@ 2014-03-07 4:57 ` Chenhui Zhao
2014-03-11 23:42 ` Scott Wood
2014-03-07 4:58 ` [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500 Chenhui Zhao
` (5 subsequent siblings)
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:57 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
There is a RCPM (Run Control/Power Management) in Freescale QorIQ
series processors. The device performs tasks associated with device
run control and power management.
The driver implements some features: mask/unmask irq, enter/exit low
power states, freeze time base, etc.
There are two versions of register map in RCPM, which is specified by
the compatible entry in the RCPM node of device tree.
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
arch/powerpc/include/asm/fsl_guts.h | 105 ++++++++
arch/powerpc/platforms/85xx/Kconfig | 1 +
arch/powerpc/platforms/85xx/corenet_generic.c | 2 +
arch/powerpc/sysdev/Kconfig | 5 +
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/fsl_rcpm.c | 315 +++++++++++++++++++++++++
arch/powerpc/sysdev/fsl_soc.h | 24 ++
7 files changed, 453 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index 77ced0b..492534a 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -185,5 +185,110 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
#endif
+struct ccsr_rcpm_v1 {
+ u8 res0000[4];
+ __be32 cdozsr; /* 0x0004 Core Doze Status Register */
+ u8 res0008[4];
+ __be32 cdozcr; /* 0x000c Core Doze Control Register */
+ u8 res0010[4];
+ __be32 cnapsr; /* 0x0014 Core Nap Status Register */
+ u8 res0018[4];
+ __be32 cnapcr; /* 0x001c Core Nap Control Register */
+ u8 res0020[4];
+ __be32 cdozpsr; /* 0x0024 Core Doze Previous Status Register */
+ u8 res0028[4];
+ __be32 cnappsr; /* 0x002c Core Nap Previous Status Register */
+ u8 res0030[4];
+ __be32 cwaitsr; /* 0x0034 Core Wait Status Register */
+ u8 res0038[4];
+ __be32 cwdtdsr; /* 0x003c Core Watchdog Detect Status Register */
+ __be32 powmgtcsr; /* 0x0040 Power Mangement Control&Status Register */
+#define RCPM_POWMGTCSR_SLP 0x00020000
+ u8 res0044[12];
+ __be32 ippdexpcr; /* 0x0050 IP Powerdown Exception Control Register */
+ u8 res0054[16];
+ __be32 cpmimr; /* 0x0064 Core PM IRQ Mask Register */
+ u8 res0068[4];
+ __be32 cpmcimr; /* 0x006c Core PM Critical IRQ Mask Register */
+ u8 res0070[4];
+ __be32 cpmmcmr; /* 0x0074 Core PM Machine Check Mask Register */
+ u8 res0078[4];
+ __be32 cpmnmimr; /* 0x007c Core PM NMI Mask Register */
+ u8 res0080[4];
+ __be32 ctbenr; /* 0x0084 Core Time Base Enable Register */
+ u8 res0088[4];
+ __be32 ctbckselr; /* 0x008c Core Time Base Clock Select Register */
+ u8 res0090[4];
+ __be32 ctbhltcr; /* 0x0094 Core Time Base Halt Control Register */
+ u8 res0098[4];
+ __be32 cmcpmaskcr; /* 0x00a4 Core Machine Check Mask Register */
+};
+
+struct ccsr_rcpm_v2 {
+ u8 res_00[12];
+ u32 tph10sr0; /* Thread PH10 Status Register */
+ u8 res_10[12];
+ u32 tph10setr0; /* Thread PH10 Set Control Register */
+ u8 res_20[12];
+ u32 tph10clrr0; /* Thread PH10 Clear Control Register */
+ u8 res_30[12];
+ u32 tph10psr0; /* Thread PH10 Previous Status Register */
+ u8 res_40[12];
+ u32 twaitsr0; /* Thread Wait Status Register */
+ u8 res_50[96];
+ u32 pcph15sr; /* Physical Core PH15 Status Register */
+ u32 pcph15setr; /* Physical Core PH15 Set Control Register */
+ u32 pcph15clrr; /* Physical Core PH15 Clear Control Register */
+ u32 pcph15psr; /* Physical Core PH15 Prev Status Register */
+ u8 res_c0[16];
+ u32 pcph20sr; /* Physical Core PH20 Status Register */
+ u32 pcph20setr; /* Physical Core PH20 Set Control Register */
+ u32 pcph20clrr; /* Physical Core PH20 Clear Control Register */
+ u32 pcph20psr; /* Physical Core PH20 Prev Status Register */
+ u32 pcpw20sr; /* Physical Core PW20 Status Register */
+ u8 res_e0[12];
+ u32 pcph30sr; /* Physical Core PH30 Status Register */
+ u32 pcph30setr; /* Physical Core PH30 Set Control Register */
+ u32 pcph30clrr; /* Physical Core PH30 Clear Control Register */
+ u32 pcph30psr; /* Physical Core PH30 Prev Status Register */
+ u8 res_100[32];
+ u32 ippwrgatecr; /* IP Power Gating Control Register */
+ u8 res_124[12];
+ u32 powmgtcsr; /* Power Management Control & Status Reg */
+#define RCPM_POWMGTCSR_LPM20_RQ 0x00100000
+#define RCPM_POWMGTCSR_LPM20_ST 0x00000200
+#define RCPM_POWMGTCSR_P_LPM20_ST 0x00000100
+ u8 res_134[12];
+ u32 ippdexpcr[4]; /* IP Powerdown Exception Control Reg */
+ u8 res_150[12];
+ u32 tpmimr0; /* Thread PM Interrupt Mask Reg */
+ u8 res_160[12];
+ u32 tpmcimr0; /* Thread PM Crit Interrupt Mask Reg */
+ u8 res_170[12];
+ u32 tpmmcmr0; /* Thread PM Machine Check Interrupt Mask Reg */
+ u8 res_180[12];
+ u32 tpmnmimr0; /* Thread PM NMI Mask Reg */
+ u8 res_190[12];
+ u32 tmcpmaskcr0; /* Thread Machine Check Mask Control Reg */
+ u32 pctbenr; /* Physical Core Time Base Enable Reg */
+ u32 pctbclkselr; /* Physical Core Time Base Clock Select */
+ u32 tbclkdivr; /* Time Base Clock Divider Register */
+ u8 res_1ac[4];
+ u32 ttbhltcr[4]; /* Thread Time Base Halt Control Register */
+ u32 clpcl10sr; /* Cluster PCL10 Status Register */
+ u32 clpcl10setr; /* Cluster PCL30 Set Control Register */
+ u32 clpcl10clrr; /* Cluster PCL30 Clear Control Register */
+ u32 clpcl10psr; /* Cluster PCL30 Prev Status Register */
+ u32 cddslpsetr; /* Core Domain Deep Sleep Set Register */
+ u32 cddslpclrr; /* Core Domain Deep Sleep Clear Register */
+ u32 cdpwroksetr; /* Core Domain Power OK Set Register */
+ u32 cdpwrokclrr; /* Core Domain Power OK Clear Register */
+ u32 cdpwrensr; /* Core Domain Power Enable Status Register */
+ u32 cddslsr; /* Core Domain Deep Sleep Status Register */
+ u8 res_1e8[8];
+ u32 dslpcntcr[8]; /* Deep Sleep Counter Cfg Register */
+ u8 res_300[3568];
+};
+
#endif
#endif
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index c17aae8..54d8843 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -8,6 +8,7 @@ menuconfig FSL_SOC_BOOKE
select FSL_PCI if PCI
select SERIAL_8250_EXTENDED if SERIAL_8250
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
+ select FSL_CORENET_RCPM if PPC_E500MC
default y
if FSL_SOC_BOOKE
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index b756f3d..3fdf9f3 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -56,6 +56,8 @@ void __init corenet_gen_setup_arch(void)
swiotlb_detect_4g();
+ fsl_rcpm_init();
+
pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
}
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 7baa70d..f6e7cde 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -34,3 +34,8 @@ config SCOM_DEBUGFS
config GE_FPGA
bool
default n
+
+config FSL_CORENET_RCPM
+ bool
+ help
+ This option enables support for RCPM (Run Control/Power Management).
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f67ac90..a6ada64 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
+obj-$(CONFIG_FSL_CORENET_RCPM) += fsl_rcpm.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
new file mode 100644
index 0000000..493fcae
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -0,0 +1,315 @@
+/*
+ * RCPM(Run Control/Power Management) support
+ *
+ * Copyright 2012-2014 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.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/types.h>
+#include <linux/errno.h>
+#include <linux/of_address.h>
+#include <linux/export.h>
+
+#include <asm/io.h>
+#include <asm/fsl_guts.h>
+#include <asm/cputhreads.h>
+#include <sysdev/fsl_soc.h>
+
+const struct fsl_pm_ops *qoriq_pm_ops;
+
+static struct ccsr_rcpm_v1 __iomem *rcpm_v1_regs;
+static struct ccsr_rcpm_v2 __iomem *rcpm_v2_regs;
+
+static void rcpm_v1_irq_mask(int cpu)
+{
+ int hw_cpu = get_hard_smp_processor_id(cpu);
+ unsigned int mask = 1 << hw_cpu;
+
+ setbits32(&rcpm_v1_regs->cpmimr, mask);
+ setbits32(&rcpm_v1_regs->cpmcimr, mask);
+ setbits32(&rcpm_v1_regs->cpmmcmr, mask);
+ setbits32(&rcpm_v1_regs->cpmnmimr, mask);
+}
+
+static void rcpm_v1_irq_unmask(int cpu)
+{
+ int hw_cpu = get_hard_smp_processor_id(cpu);
+ unsigned int mask = 1 << hw_cpu;
+
+ clrbits32(&rcpm_v1_regs->cpmimr, mask);
+ clrbits32(&rcpm_v1_regs->cpmcimr, mask);
+ clrbits32(&rcpm_v1_regs->cpmmcmr, mask);
+ clrbits32(&rcpm_v1_regs->cpmnmimr, mask);
+}
+
+static void rcpm_v1_set_ip_power(int enable, u32 mask)
+{
+ if (enable)
+ setbits32(&rcpm_v1_regs->ippdexpcr, mask);
+ else
+ clrbits32(&rcpm_v1_regs->ippdexpcr, mask);
+}
+
+static void rcpm_v1_cpu_enter_state(int cpu, int state)
+{
+ unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+ unsigned int mask = 1 << hw_cpu;
+
+ switch (state) {
+ case E500_PM_PH10:
+ setbits32(&rcpm_v1_regs->cdozcr, mask);
+ break;
+ case E500_PM_PH15:
+ setbits32(&rcpm_v1_regs->cnapcr, mask);
+ break;
+ default:
+ pr_err("Unknown cpu PM state\n");
+ break;
+ }
+}
+
+static void rcpm_v1_cpu_exit_state(int cpu, int state)
+{
+ unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+ unsigned int mask = 1 << hw_cpu;
+
+ switch (state) {
+ case E500_PM_PH10:
+ clrbits32(&rcpm_v1_regs->cdozcr, mask);
+ break;
+ case E500_PM_PH15:
+ clrbits32(&rcpm_v1_regs->cnapcr, mask);
+ break;
+ default:
+ pr_err("Unknown cpu PM state\n");
+ break;
+ }
+}
+
+static int rcpm_v1_plat_enter_state(int state)
+{
+ u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
+ int ret = 0;
+ int result;
+
+ switch (state) {
+ case PLAT_PM_SLEEP:
+ setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
+
+ /* At this point, the device is in sleep mode. */
+
+ /* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
+ result = spin_event_timeout(
+ !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_SLP), 10000, 10);
+ if (!result) {
+ pr_err("%s: timeout waiting for SLP bit to be cleared\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ }
+ break;
+ default:
+ pr_err("Unsupported platform PM state\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void rcpm_v1_freeze_time_base(int freeze)
+{
+ u32 *tben_reg = &rcpm_v1_regs->ctbenr;
+ static u32 mask;
+
+ if (freeze) {
+ mask = in_be32(tben_reg);
+ clrbits32(tben_reg, mask);
+ } else {
+ setbits32(tben_reg, mask);
+ }
+
+ /* read back to push the previous write */
+ in_be32(tben_reg);
+}
+
+static void rcpm_v2_freeze_time_base(int freeze)
+{
+ u32 *tben_reg = &rcpm_v2_regs->pctbenr;
+ static u32 mask;
+
+ if (freeze) {
+ mask = in_be32(tben_reg);
+ clrbits32(tben_reg, mask);
+ } else {
+ setbits32(tben_reg, mask);
+ }
+
+ /* read back to push the previous write */
+ in_be32(tben_reg);
+}
+
+static void rcpm_v2_irq_mask(int cpu)
+{
+ int hw_cpu = get_hard_smp_processor_id(cpu);
+ unsigned int mask = 1 << hw_cpu;
+
+ setbits32(&rcpm_v2_regs->tpmimr0, mask);
+ setbits32(&rcpm_v2_regs->tpmcimr0, mask);
+ setbits32(&rcpm_v2_regs->tpmmcmr0, mask);
+ setbits32(&rcpm_v2_regs->tpmnmimr0, mask);
+}
+
+static void rcpm_v2_irq_unmask(int cpu)
+{
+ int hw_cpu = get_hard_smp_processor_id(cpu);
+ unsigned int mask = 1 << hw_cpu;
+
+ clrbits32(&rcpm_v2_regs->tpmimr0, mask);
+ clrbits32(&rcpm_v2_regs->tpmcimr0, mask);
+ clrbits32(&rcpm_v2_regs->tpmmcmr0, mask);
+ clrbits32(&rcpm_v2_regs->tpmnmimr0, mask);
+}
+
+static void rcpm_v2_set_ip_power(int enable, u32 mask)
+{
+ if (enable)
+ /* enable power of IP blocks in deep sleep mode */
+ setbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
+ else
+ clrbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
+}
+
+static void rcpm_v2_cpu_enter_state(int cpu, int state)
+{
+ unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+ u32 mask = 1 << cpu_core_index_of_thread(hw_cpu);
+
+ switch (state) {
+ case E500_PM_PH10:
+ /* one bit corresponds to one thread for PH10 of 6500 */
+ setbits32(&rcpm_v2_regs->tph10setr0, 1 << hw_cpu);
+ break;
+ case E500_PM_PH15:
+ setbits32(&rcpm_v2_regs->pcph15setr, mask);
+ break;
+ case E500_PM_PH20:
+ setbits32(&rcpm_v2_regs->pcph20setr, mask);
+ break;
+ case E500_PM_PH30:
+ setbits32(&rcpm_v2_regs->pcph30setr, mask);
+ break;
+ default:
+ pr_err("Unsupported cpu PM state\n");
+ }
+}
+
+static void rcpm_v2_cpu_exit_state(int cpu, int state)
+{
+ unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+ u32 mask = 1 << cpu_core_index_of_thread(hw_cpu);
+
+ switch (state) {
+ case E500_PM_PH10:
+ setbits32(&rcpm_v2_regs->tph10clrr0, 1 << hw_cpu);
+ break;
+ case E500_PM_PH15:
+ setbits32(&rcpm_v2_regs->pcph15clrr, mask);
+ break;
+ case E500_PM_PH20:
+ setbits32(&rcpm_v2_regs->pcph20clrr, mask);
+ break;
+ case E500_PM_PH30:
+ setbits32(&rcpm_v2_regs->pcph30clrr, mask);
+ break;
+ default:
+ pr_err("Unsupported cpu PM state\n");
+ }
+}
+
+static int rcpm_v2_plat_enter_state(int state)
+{
+ u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr;
+ int ret = 0;
+ int result;
+
+ switch (state) {
+ case PLAT_PM_LPM20:
+ /* clear previous LPM20 status */
+ setbits32(pmcsr_reg, RCPM_POWMGTCSR_P_LPM20_ST);
+ /* enter LPM20 status */
+ setbits32(pmcsr_reg, RCPM_POWMGTCSR_LPM20_RQ);
+
+ /* At this point, the device is in LPM20 status. */
+
+ /* resume ... */
+ result = spin_event_timeout(
+ !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_LPM20_ST), 10000, 10);
+ if (!result) {
+ pr_err("%s: timeout waiting for LPM20 bit to be cleared\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ }
+ break;
+ default:
+ pr_err("Unsupported platform PM state\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct fsl_pm_ops qoriq_rcpm_v1_ops = {
+ .irq_mask = rcpm_v1_irq_mask,
+ .irq_unmask = rcpm_v1_irq_unmask,
+ .cpu_enter_state = rcpm_v1_cpu_enter_state,
+ .cpu_exit_state = rcpm_v1_cpu_exit_state,
+ .plat_enter_state = rcpm_v1_plat_enter_state,
+ .set_ip_power = rcpm_v1_set_ip_power,
+ .freeze_time_base = rcpm_v1_freeze_time_base,
+};
+
+static const struct fsl_pm_ops qoriq_rcpm_v2_ops = {
+ .irq_mask = rcpm_v2_irq_mask,
+ .irq_unmask = rcpm_v2_irq_unmask,
+ .cpu_enter_state = rcpm_v2_cpu_enter_state,
+ .cpu_exit_state = rcpm_v2_cpu_exit_state,
+ .plat_enter_state = rcpm_v2_plat_enter_state,
+ .set_ip_power = rcpm_v2_set_ip_power,
+ .freeze_time_base = rcpm_v2_freeze_time_base,
+};
+
+int fsl_rcpm_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
+ if (np) {
+ rcpm_v2_regs = of_iomap(np, 0);
+ of_node_put(np);
+ if (!rcpm_v2_regs)
+ return -ENOMEM;
+
+ qoriq_pm_ops = &qoriq_rcpm_v2_ops;
+
+ } else {
+ np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-1.0");
+ if (np) {
+ rcpm_v1_regs = of_iomap(np, 0);
+ of_node_put(np);
+ if (!rcpm_v1_regs)
+ return -ENOMEM;
+
+ qoriq_pm_ops = &qoriq_rcpm_v1_ops;
+
+ } else {
+ pr_err("%s: can't find the rcpm node.\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 4c5a19e..9b9a34a 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -45,5 +45,29 @@ extern struct platform_diu_data_ops diu_ops;
void fsl_hv_restart(char *cmd);
void fsl_hv_halt(void);
+struct fsl_pm_ops {
+ void (*irq_mask)(int cpu);
+ void (*irq_unmask)(int cpu);
+ void (*cpu_enter_state)(int cpu, int state);
+ void (*cpu_exit_state)(int cpu, int state);
+ int (*plat_enter_state)(int state);
+ void (*freeze_time_base)(int freeze);
+ void (*set_ip_power)(int enable, u32 mask);
+};
+
+extern const struct fsl_pm_ops *qoriq_pm_ops;
+
+#define E500_PM_PH10 1
+#define E500_PM_PH15 2
+#define E500_PM_PH20 3
+#define E500_PM_PH30 4
+#define E500_PM_DOZE E500_PM_PH10
+#define E500_PM_NAP E500_PM_PH15
+
+#define PLAT_PM_SLEEP 20
+#define PLAT_PM_LPM20 30
+
+extern int fsl_rcpm_init(void);
+
#endif
#endif
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 3/9] powerpc/rcpm: add RCPM driver
2014-03-07 4:57 ` [PATCH 3/9] powerpc/rcpm: add RCPM driver Chenhui Zhao
@ 2014-03-11 23:42 ` Scott Wood
2014-03-12 3:59 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-11 23:42 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:57 +0800, Chenhui Zhao wrote:
> diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
> index b756f3d..3fdf9f3 100644
> --- a/arch/powerpc/platforms/85xx/corenet_generic.c
> +++ b/arch/powerpc/platforms/85xx/corenet_generic.c
> @@ -56,6 +56,8 @@ void __init corenet_gen_setup_arch(void)
>
> swiotlb_detect_4g();
>
> + fsl_rcpm_init();
> +
> pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
RCPM is not board-specific. Why is this in board code?
> +static void rcpm_v1_cpu_enter_state(int cpu, int state)
> +{
> + unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
> + unsigned int mask = 1 << hw_cpu;
> +
> + switch (state) {
> + case E500_PM_PH10:
> + setbits32(&rcpm_v1_regs->cdozcr, mask);
> + break;
> + case E500_PM_PH15:
> + setbits32(&rcpm_v1_regs->cnapcr, mask);
> + break;
> + default:
> + pr_err("Unknown cpu PM state\n");
> + break;
> + }
> +}
Put __func__ in error messages -- and for "unknown value" type messages,
print the value.
> +static int rcpm_v1_plat_enter_state(int state)
> +{
> + u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
> + int ret = 0;
> + int result;
> +
> + switch (state) {
> + case PLAT_PM_SLEEP:
> + setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
> +
> + /* At this point, the device is in sleep mode. */
> +
> + /* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
> + result = spin_event_timeout(
> + !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_SLP), 10000, 10);
> + if (!result) {
> + pr_err("%s: timeout waiting for SLP bit to be cleared\n",
> + __func__);
Why are you indenting continuation lines with only two spaces (and yet
still not aligning with anything)?
> + ret = -ETIMEDOUT;
> + }
> + break;
> + default:
> + pr_err("Unsupported platform PM state\n");
> + ret = -EINVAL;
> + }
> +
> + return ret;
> +}
> +
> +static void rcpm_v1_freeze_time_base(int freeze)
> +{
> + u32 *tben_reg = &rcpm_v1_regs->ctbenr;
> + static u32 mask;
> +
> + if (freeze) {
> + mask = in_be32(tben_reg);
> + clrbits32(tben_reg, mask);
> + } else {
> + setbits32(tben_reg, mask);
> + }
> +
> + /* read back to push the previous write */
> + in_be32(tben_reg);
> +}
> +
> +static void rcpm_v2_freeze_time_base(int freeze)
> +{
> + u32 *tben_reg = &rcpm_v2_regs->pctbenr;
> + static u32 mask;
> +
> + if (freeze) {
> + mask = in_be32(tben_reg);
> + clrbits32(tben_reg, mask);
> + } else {
> + setbits32(tben_reg, mask);
> + }
> +
> + /* read back to push the previous write */
> + in_be32(tben_reg);
> +}
It looks like the only difference between these two functions is how you
calculate tben_reg -- factor the rest out into a single function.
> +int fsl_rcpm_init(void)
> +{
> + struct device_node *np;
> +
> + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
> + if (np) {
> + rcpm_v2_regs = of_iomap(np, 0);
> + of_node_put(np);
> + if (!rcpm_v2_regs)
> + return -ENOMEM;
> +
> + qoriq_pm_ops = &qoriq_rcpm_v2_ops;
> +
> + } else {
> + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-1.0");
> + if (np) {
> + rcpm_v1_regs = of_iomap(np, 0);
> + of_node_put(np);
> + if (!rcpm_v1_regs)
> + return -ENOMEM;
> +
> + qoriq_pm_ops = &qoriq_rcpm_v1_ops;
> +
> + } else {
> + pr_err("%s: can't find the rcpm node.\n", __func__);
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> +}
Why isn't this a proper platform driver?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 3/9] powerpc/rcpm: add RCPM driver
2014-03-11 23:42 ` Scott Wood
@ 2014-03-12 3:59 ` Chenhui Zhao
2014-03-14 22:34 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 3:59 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 11, 2014 at 06:42:51PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:57 +0800, Chenhui Zhao wrote:
> > diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
> > index b756f3d..3fdf9f3 100644
> > --- a/arch/powerpc/platforms/85xx/corenet_generic.c
> > +++ b/arch/powerpc/platforms/85xx/corenet_generic.c
> > @@ -56,6 +56,8 @@ void __init corenet_gen_setup_arch(void)
> >
> > swiotlb_detect_4g();
> >
> > + fsl_rcpm_init();
> > +
> > pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
>
> RCPM is not board-specific. Why is this in board code?
Init the RCPM driver in the early stage before smp_init(). Because
the time base sync calls a callback function .freeze_time_base()
in the RCPM driver.
Will use early_initcall() instead.
>
> > +static void rcpm_v1_cpu_enter_state(int cpu, int state)
> > +{
> > + unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
> > + unsigned int mask = 1 << hw_cpu;
> > +
> > + switch (state) {
> > + case E500_PM_PH10:
> > + setbits32(&rcpm_v1_regs->cdozcr, mask);
> > + break;
> > + case E500_PM_PH15:
> > + setbits32(&rcpm_v1_regs->cnapcr, mask);
> > + break;
> > + default:
> > + pr_err("Unknown cpu PM state\n");
> > + break;
> > + }
> > +}
>
> Put __func__ in error messages -- and for "unknown value" type messages,
> print the value.
OK.
>
>
> > +static int rcpm_v1_plat_enter_state(int state)
> > +{
> > + u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
> > + int ret = 0;
> > + int result;
> > +
> > + switch (state) {
> > + case PLAT_PM_SLEEP:
> > + setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
> > +
> > + /* At this point, the device is in sleep mode. */
> > +
> > + /* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
> > + result = spin_event_timeout(
> > + !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_SLP), 10000, 10);
> > + if (!result) {
> > + pr_err("%s: timeout waiting for SLP bit to be cleared\n",
> > + __func__);
>
> Why are you indenting continuation lines with only two spaces (and yet
> still not aligning with anything)?
Will align with the previous parenthesis.
>
> > + ret = -ETIMEDOUT;
> > + }
> > + break;
> > + default:
> > + pr_err("Unsupported platform PM state\n");
> > + ret = -EINVAL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void rcpm_v1_freeze_time_base(int freeze)
> > +{
> > + u32 *tben_reg = &rcpm_v1_regs->ctbenr;
> > + static u32 mask;
> > +
> > + if (freeze) {
> > + mask = in_be32(tben_reg);
> > + clrbits32(tben_reg, mask);
> > + } else {
> > + setbits32(tben_reg, mask);
> > + }
> > +
> > + /* read back to push the previous write */
> > + in_be32(tben_reg);
> > +}
> > +
> > +static void rcpm_v2_freeze_time_base(int freeze)
> > +{
> > + u32 *tben_reg = &rcpm_v2_regs->pctbenr;
> > + static u32 mask;
> > +
> > + if (freeze) {
> > + mask = in_be32(tben_reg);
> > + clrbits32(tben_reg, mask);
> > + } else {
> > + setbits32(tben_reg, mask);
> > + }
> > +
> > + /* read back to push the previous write */
> > + in_be32(tben_reg);
> > +}
>
> It looks like the only difference between these two functions is how you
> calculate tben_reg -- factor the rest out into a single function.
Yes. Will factor them out into a single function.
>
> > +int fsl_rcpm_init(void)
> > +{
> > + struct device_node *np;
> > +
> > + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
> > + if (np) {
> > + rcpm_v2_regs = of_iomap(np, 0);
> > + of_node_put(np);
> > + if (!rcpm_v2_regs)
> > + return -ENOMEM;
> > +
> > + qoriq_pm_ops = &qoriq_rcpm_v2_ops;
> > +
> > + } else {
> > + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-1.0");
> > + if (np) {
> > + rcpm_v1_regs = of_iomap(np, 0);
> > + of_node_put(np);
> > + if (!rcpm_v1_regs)
> > + return -ENOMEM;
> > +
> > + qoriq_pm_ops = &qoriq_rcpm_v1_ops;
> > +
> > + } else {
> > + pr_err("%s: can't find the rcpm node.\n", __func__);
> > + return -EINVAL;
> > + }
> > + }
> > +
> > + return 0;
> > +}
>
> Why isn't this a proper platform driver?
>
> -Scott
The RCPM is not a single function IP block, instead it is a collection
of device run control and power management. It would be called by other
drivers and functions. For example, the callback .freeze_time_base()
need to be called at early stage of kernel init. Therefore, it would be
better to init it at early stage.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 3/9] powerpc/rcpm: add RCPM driver
2014-03-12 3:59 ` Chenhui Zhao
@ 2014-03-14 22:34 ` Scott Wood
0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2014-03-14 22:34 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Wed, 2014-03-12 at 11:59 +0800, Chenhui Zhao wrote:
> On Tue, Mar 11, 2014 at 06:42:51PM -0500, Scott Wood wrote:
> > On Fri, 2014-03-07 at 12:57 +0800, Chenhui Zhao wrote:
> > > +int fsl_rcpm_init(void)
> > > +{
> > > + struct device_node *np;
> > > +
> > > + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
> > > + if (np) {
> > > + rcpm_v2_regs = of_iomap(np, 0);
> > > + of_node_put(np);
> > > + if (!rcpm_v2_regs)
> > > + return -ENOMEM;
> > > +
> > > + qoriq_pm_ops = &qoriq_rcpm_v2_ops;
> > > +
> > > + } else {
> > > + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-1.0");
> > > + if (np) {
> > > + rcpm_v1_regs = of_iomap(np, 0);
> > > + of_node_put(np);
> > > + if (!rcpm_v1_regs)
> > > + return -ENOMEM;
> > > +
> > > + qoriq_pm_ops = &qoriq_rcpm_v1_ops;
> > > +
> > > + } else {
> > > + pr_err("%s: can't find the rcpm node.\n", __func__);
> > > + return -EINVAL;
> > > + }
> > > + }
> > > +
> > > + return 0;
> > > +}
> >
> > Why isn't this a proper platform driver?
> >
> > -Scott
>
> The RCPM is not a single function IP block, instead it is a collection
> of device run control and power management. It would be called by other
> drivers and functions. For example, the callback .freeze_time_base()
> need to be called at early stage of kernel init. Therefore, it would be
> better to init it at early stage.
OK, but consider using of_find_matching_node_and_match().
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
2014-03-07 4:57 ` [PATCH 2/9] powerpc/cache: add cache flush operation for various e500 Chenhui Zhao
2014-03-07 4:57 ` [PATCH 3/9] powerpc/rcpm: add RCPM driver Chenhui Zhao
@ 2014-03-07 4:58 ` Chenhui Zhao
2014-03-11 23:48 ` Scott Wood
2014-03-07 4:58 ` [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit Chenhui Zhao
` (4 subsequent siblings)
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
Implemented CPU hotplug on e500mc and e5500. On e5500 both 32-bit and
64-bit modes can work. Used some callback functions implemented in RCPM
driver.
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
arch/powerpc/Kconfig | 2 +-
arch/powerpc/kernel/smp.c | 6 ++-
arch/powerpc/mm/tlb_nohash.c | 6 ++-
arch/powerpc/platforms/85xx/smp.c | 94 ++++++++++++++++++++++++++++++-------
4 files changed, 87 insertions(+), 21 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a5e5d2e..05f6323 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -362,7 +362,7 @@ config SWIOTLB
config HOTPLUG_CPU
bool "Support for enabling/disabling CPUs"
depends on SMP && (PPC_PSERIES || \
- PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
+ PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE)
---help---
Say Y here to be able to disable and re-enable individual
CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ac2621a..f3f4401 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -405,8 +405,12 @@ void generic_cpu_die(unsigned int cpu)
for (i = 0; i < 100; i++) {
smp_rmb();
- if (per_cpu(cpu_state, cpu) == CPU_DEAD)
+ if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+#ifdef CONFIG_PPC64
+ paca[cpu].cpu_start = 0;
+#endif
return;
+ }
msleep(100);
}
printk(KERN_ERR "CPU%d didn't die...\n", cpu);
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index b37a58e..d24e06c 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -648,8 +648,10 @@ static void __early_init_mmu(int boot_cpu)
num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
linear_map_top = map_mem_in_cams(linear_map_top, num_cams);
- /* limit memory so we dont have linear faults */
- memblock_enforce_memory_limit(linear_map_top);
+ if (boot_cpu) {
+ /* limit memory so we dont have linear faults */
+ memblock_enforce_memory_limit(linear_map_top);
+ }
if (book3e_htw_mode == PPC_HTW_NONE) {
patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 2e5911e..0047883 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -19,6 +19,7 @@
#include <linux/kexec.h>
#include <linux/highmem.h>
#include <linux/cpu.h>
+#include <linux/smp.h>
#include <asm/machdep.h>
#include <asm/pgtable.h>
@@ -46,6 +47,17 @@ static u64 timebase;
static int tb_req;
static int tb_valid;
+#ifdef CONFIG_PPC_E500MC
+/* specify the cpu PM state when cpu dies, PH15/NAP is the default */
+int qoriq_cpu_die_state = E500_PM_PH15;
+#endif
+
+#ifdef CONFIG_PPC_E500MC
+static void mpc85xx_timebase_freeze(int freeze)
+{
+ qoriq_pm_ops->freeze_time_base(freeze);
+}
+#else
static void mpc85xx_timebase_freeze(int freeze)
{
uint32_t mask;
@@ -58,6 +70,7 @@ static void mpc85xx_timebase_freeze(int freeze)
in_be32(&guts->devdisr);
}
+#endif
static void mpc85xx_give_timebase(void)
{
@@ -125,6 +138,34 @@ static void mpc85xx_take_timebase(void)
}
#ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_PPC_E500MC
+static void qoriq_cpu_die(void)
+{
+ unsigned int cpu = smp_processor_id();
+
+ local_irq_disable();
+#ifdef CONFIG_PPC64
+ __hard_irq_disable();
+#endif
+ idle_task_exit();
+
+ if (qoriq_pm_ops->irq_mask)
+ qoriq_pm_ops->irq_mask(cpu);
+
+ mtspr(SPRN_TCR, 0);
+ mtspr(SPRN_TSR, mfspr(SPRN_TSR));
+
+ generic_set_cpu_dead(cpu);
+
+ if (cur_cpu_spec && cur_cpu_spec->cpu_flush_caches)
+ cur_cpu_spec->cpu_flush_caches();
+
+ qoriq_pm_ops->cpu_enter_state(cpu, qoriq_cpu_die_state);
+
+ while (1)
+ ;
+}
+#else
static void smp_85xx_mach_cpu_die(void)
{
unsigned int cpu = smp_processor_id();
@@ -155,6 +196,7 @@ static void smp_85xx_mach_cpu_die(void)
;
}
#endif
+#endif
static inline void flush_spin_table(void *spin_table)
{
@@ -208,11 +250,8 @@ static int smp_85xx_kick_cpu(int nr)
spin_table = phys_to_virt(*cpu_rel_addr);
local_irq_save(flags);
-#ifdef CONFIG_PPC32
-#ifdef CONFIG_HOTPLUG_CPU
- /* Corresponding to generic_set_cpu_dead() */
- generic_set_cpu_up(nr);
+#ifdef CONFIG_HOTPLUG_CPU
if (system_state == SYSTEM_RUNNING) {
/*
* To keep it compatible with old boot program which uses
@@ -225,6 +264,12 @@ static int smp_85xx_kick_cpu(int nr)
out_be32(&spin_table->addr_l, 0);
flush_spin_table(spin_table);
+#ifdef CONFIG_PPC_E500MC
+ /* Due to an erratum, wake the core before reset. */
+ if (qoriq_pm_ops && qoriq_pm_ops->cpu_exit_state)
+ qoriq_pm_ops->cpu_exit_state(nr, qoriq_cpu_die_state);
+#endif
+
/*
* We don't set the BPTR register here since it already points
* to the boot page properly.
@@ -247,13 +292,30 @@ static int smp_85xx_kick_cpu(int nr)
/* clear the acknowledge status */
__secondary_hold_acknowledge = -1;
+
+#ifdef CONFIG_PPC_E500MC
+ if (qoriq_pm_ops->irq_unmask)
+ qoriq_pm_ops->irq_unmask(nr);
+#endif
}
+
+ /* Corresponding to generic_set_cpu_dead() */
+ generic_set_cpu_up(nr);
#endif
+
flush_spin_table(spin_table);
out_be32(&spin_table->pir, hw_cpu);
+#ifdef CONFIG_PPC32
out_be32(&spin_table->addr_l, __pa(__early_start));
+#else
+ out_be32(&spin_table->addr_h,
+ __pa(*(u64 *)generic_secondary_smp_init) >> 32);
+ out_be32(&spin_table->addr_l,
+ __pa(*(u64 *)generic_secondary_smp_init) & 0xffffffff);
+#endif
flush_spin_table(spin_table);
+#ifdef CONFIG_PPC32
/* Wait a bit for the CPU to ack. */
if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
10000, 100)) {
@@ -262,17 +324,10 @@ static int smp_85xx_kick_cpu(int nr)
ret = -ENOENT;
goto out;
}
-out:
#else
smp_generic_kick_cpu(nr);
-
- flush_spin_table(spin_table);
- out_be32(&spin_table->pir, hw_cpu);
- out_be64((u64 *)(&spin_table->addr_h),
- __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
- flush_spin_table(spin_table);
#endif
-
+out:
local_irq_restore(flags);
if (ioremappable)
@@ -445,13 +500,18 @@ void __init mpc85xx_smp_init(void)
__func__);
return;
}
- smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
- smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
-#ifdef CONFIG_HOTPLUG_CPU
- ppc_md.cpu_die = smp_85xx_mach_cpu_die;
-#endif
}
+ smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+ smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+
+#ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_PPC_E500MC
+ ppc_md.cpu_die = qoriq_cpu_die;
+#else
+ ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
+#endif
smp_ops = &smp_85xx_ops;
#ifdef CONFIG_KEXEC
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500
2014-03-07 4:58 ` [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500 Chenhui Zhao
@ 2014-03-11 23:48 ` Scott Wood
2014-03-12 4:34 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-11 23:48 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
> index ac2621a..f3f4401 100644
> --- a/arch/powerpc/kernel/smp.c
> +++ b/arch/powerpc/kernel/smp.c
> @@ -405,8 +405,12 @@ void generic_cpu_die(unsigned int cpu)
>
> for (i = 0; i < 100; i++) {
> smp_rmb();
> - if (per_cpu(cpu_state, cpu) == CPU_DEAD)
> + if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
> +#ifdef CONFIG_PPC64
> + paca[cpu].cpu_start = 0;
> +#endif
Why wasn't this needed by previous ppc64 machines?
> diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
> index 2e5911e..0047883 100644
> --- a/arch/powerpc/platforms/85xx/smp.c
> +++ b/arch/powerpc/platforms/85xx/smp.c
> @@ -19,6 +19,7 @@
> #include <linux/kexec.h>
> #include <linux/highmem.h>
> #include <linux/cpu.h>
> +#include <linux/smp.h>
>
> #include <asm/machdep.h>
> #include <asm/pgtable.h>
> @@ -46,6 +47,17 @@ static u64 timebase;
> static int tb_req;
> static int tb_valid;
>
> +#ifdef CONFIG_PPC_E500MC
> +/* specify the cpu PM state when cpu dies, PH15/NAP is the default */
> +int qoriq_cpu_die_state = E500_PM_PH15;
> +#endif
static? Is there any way to modify this other than modifying source
code?
BTW, QorIQ doesn't imply an e500mc derivative.
> @@ -125,6 +138,34 @@ static void mpc85xx_take_timebase(void)
> }
>
> #ifdef CONFIG_HOTPLUG_CPU
> +#ifdef CONFIG_PPC_E500MC
> +static void qoriq_cpu_die(void)
> +{
> + unsigned int cpu = smp_processor_id();
> +
> + local_irq_disable();
> +#ifdef CONFIG_PPC64
> + __hard_irq_disable();
> +#endif
Why this instead of one call to hard_irq_disable() (no leading
underscores)?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500
2014-03-11 23:48 ` Scott Wood
@ 2014-03-12 4:34 ` Chenhui Zhao
0 siblings, 0 replies; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 4:34 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 11, 2014 at 06:48:13PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
> > index ac2621a..f3f4401 100644
> > --- a/arch/powerpc/kernel/smp.c
> > +++ b/arch/powerpc/kernel/smp.c
> > @@ -405,8 +405,12 @@ void generic_cpu_die(unsigned int cpu)
> >
> > for (i = 0; i < 100; i++) {
> > smp_rmb();
> > - if (per_cpu(cpu_state, cpu) == CPU_DEAD)
> > + if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
> > +#ifdef CONFIG_PPC64
> > + paca[cpu].cpu_start = 0;
> > +#endif
>
> Why wasn't this needed by previous ppc64 machines?
If not clear, cpu can't start in the case of cpu hotpolug.
The function pseries_cpu_die() in arch/powerpc/platforms/pseries/hotplug-cpu.c
also clears the flag.
>
> > diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
> > index 2e5911e..0047883 100644
> > --- a/arch/powerpc/platforms/85xx/smp.c
> > +++ b/arch/powerpc/platforms/85xx/smp.c
> > @@ -19,6 +19,7 @@
> > #include <linux/kexec.h>
> > #include <linux/highmem.h>
> > #include <linux/cpu.h>
> > +#include <linux/smp.h>
> >
> > #include <asm/machdep.h>
> > #include <asm/pgtable.h>
> > @@ -46,6 +47,17 @@ static u64 timebase;
> > static int tb_req;
> > static int tb_valid;
> >
> > +#ifdef CONFIG_PPC_E500MC
> > +/* specify the cpu PM state when cpu dies, PH15/NAP is the default */
> > +int qoriq_cpu_die_state = E500_PM_PH15;
> > +#endif
>
> static? Is there any way to modify this other than modifying source
> code?
>
> BTW, QorIQ doesn't imply an e500mc derivative.
Will support e500, but for now these code support e500mc derivative in
advance.
Supposed qoriq_cpu_die_state can be changed by platform init code
if the default value is not proper for a specific platform.
>
> > @@ -125,6 +138,34 @@ static void mpc85xx_take_timebase(void)
> > }
> >
> > #ifdef CONFIG_HOTPLUG_CPU
> > +#ifdef CONFIG_PPC_E500MC
> > +static void qoriq_cpu_die(void)
> > +{
> > + unsigned int cpu = smp_processor_id();
> > +
> > + local_irq_disable();
> > +#ifdef CONFIG_PPC64
> > + __hard_irq_disable();
> > +#endif
>
> Why this instead of one call to hard_irq_disable() (no leading
> underscores)?
>
> -Scott
hard_irq_disable() will clear soft_enabled again. local_irq_disable()
has cleared it.
Will use hard_irq_disable() to replace these lines.
local_irq_disable();
#ifdef CONFIG_PPC64
__hard_irq_disable();
#endif
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
` (2 preceding siblings ...)
2014-03-07 4:58 ` [PATCH 4/9] powerpc/85xx: support CPU hotplug for e500mc and e5500 Chenhui Zhao
@ 2014-03-07 4:58 ` Chenhui Zhao
2014-03-11 23:51 ` Scott Wood
2014-03-07 4:58 ` [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM Chenhui Zhao
` (3 subsequent siblings)
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
In 64-bit mode, kernel just clears the irq soft-enable flag
in struct paca_struct to disable external irqs. But, in
the case of suspend, irqs should be disabled by hardware.
Therefore, hook a function to ppc_md.suspend_disable_irqs
to really disable irqs.
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
arch/powerpc/platforms/85xx/corenet_generic.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
index 3fdf9f3..983d81f 100644
--- a/arch/powerpc/platforms/85xx/corenet_generic.c
+++ b/arch/powerpc/platforms/85xx/corenet_generic.c
@@ -32,6 +32,13 @@
#include <sysdev/fsl_pci.h>
#include "smp.h"
+#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
+static void fsl_suspend_disable_irqs(void)
+{
+ __hard_irq_disable();
+}
+#endif
+
void __init corenet_gen_pic_init(void)
{
struct mpic *mpic;
@@ -58,6 +65,11 @@ void __init corenet_gen_setup_arch(void)
fsl_rcpm_init();
+#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
+ /* physically disable irq for 64-bit mode when suspend */
+ ppc_md.suspend_disable_irqs = fsl_suspend_disable_irqs;
+#endif
+
pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
}
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit
2014-03-07 4:58 ` [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit Chenhui Zhao
@ 2014-03-11 23:51 ` Scott Wood
2014-03-12 7:46 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-11 23:51 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> In 64-bit mode, kernel just clears the irq soft-enable flag
> in struct paca_struct to disable external irqs. But, in
> the case of suspend, irqs should be disabled by hardware.
> Therefore, hook a function to ppc_md.suspend_disable_irqs
> to really disable irqs.
>
> Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> ---
> arch/powerpc/platforms/85xx/corenet_generic.c | 12 ++++++++++++
> 1 files changed, 12 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
> index 3fdf9f3..983d81f 100644
> --- a/arch/powerpc/platforms/85xx/corenet_generic.c
> +++ b/arch/powerpc/platforms/85xx/corenet_generic.c
> @@ -32,6 +32,13 @@
> #include <sysdev/fsl_pci.h>
> #include "smp.h"
>
> +#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
> +static void fsl_suspend_disable_irqs(void)
> +{
> + __hard_irq_disable();
> +}
> +#endif
Why the underscore version? Don't you want PACA_IRQ_HARD_DIS to be set?
If hard disabling is appropriate here, shouldn't we do it in
generic_suspend_disable_irqs()?
Are there any existing platforms that supply a
ppc_md.suspend_disable_irqs()? I don't see any when grepping.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit
2014-03-11 23:51 ` Scott Wood
@ 2014-03-12 7:46 ` Chenhui Zhao
2014-03-14 22:41 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 7:46 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 11, 2014 at 06:51:20PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > In 64-bit mode, kernel just clears the irq soft-enable flag
> > in struct paca_struct to disable external irqs. But, in
> > the case of suspend, irqs should be disabled by hardware.
> > Therefore, hook a function to ppc_md.suspend_disable_irqs
> > to really disable irqs.
> >
> > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > ---
> > arch/powerpc/platforms/85xx/corenet_generic.c | 12 ++++++++++++
> > 1 files changed, 12 insertions(+), 0 deletions(-)
> >
> > diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
> > index 3fdf9f3..983d81f 100644
> > --- a/arch/powerpc/platforms/85xx/corenet_generic.c
> > +++ b/arch/powerpc/platforms/85xx/corenet_generic.c
> > @@ -32,6 +32,13 @@
> > #include <sysdev/fsl_pci.h>
> > #include "smp.h"
> >
> > +#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
> > +static void fsl_suspend_disable_irqs(void)
> > +{
> > + __hard_irq_disable();
> > +}
> > +#endif
>
> Why the underscore version? Don't you want PACA_IRQ_HARD_DIS to be set?
>
> If hard disabling is appropriate here, shouldn't we do it in
> generic_suspend_disable_irqs()?
>
> Are there any existing platforms that supply a
> ppc_md.suspend_disable_irqs()? I don't see any when grepping.
>
> -Scott
Will use hard_irq_disable().
I think this is a general problem for powerpc.
Should clear MSR_EE before suspend. I agree to put it
in generic_suspend_disable_irqs().
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit
2014-03-12 7:46 ` Chenhui Zhao
@ 2014-03-14 22:41 ` Scott Wood
2014-03-17 9:37 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-14 22:41 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Wed, 2014-03-12 at 15:46 +0800, Chenhui Zhao wrote:
> On Tue, Mar 11, 2014 at 06:51:20PM -0500, Scott Wood wrote:
> > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > In 64-bit mode, kernel just clears the irq soft-enable flag
> > > in struct paca_struct to disable external irqs. But, in
> > > the case of suspend, irqs should be disabled by hardware.
> > > Therefore, hook a function to ppc_md.suspend_disable_irqs
> > > to really disable irqs.
> > >
> > > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > > ---
> > > arch/powerpc/platforms/85xx/corenet_generic.c | 12 ++++++++++++
> > > 1 files changed, 12 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
> > > index 3fdf9f3..983d81f 100644
> > > --- a/arch/powerpc/platforms/85xx/corenet_generic.c
> > > +++ b/arch/powerpc/platforms/85xx/corenet_generic.c
> > > @@ -32,6 +32,13 @@
> > > #include <sysdev/fsl_pci.h>
> > > #include "smp.h"
> > >
> > > +#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
> > > +static void fsl_suspend_disable_irqs(void)
> > > +{
> > > + __hard_irq_disable();
> > > +}
> > > +#endif
> >
> > Why the underscore version? Don't you want PACA_IRQ_HARD_DIS to be set?
> >
> > If hard disabling is appropriate here, shouldn't we do it in
> > generic_suspend_disable_irqs()?
> >
> > Are there any existing platforms that supply a
> > ppc_md.suspend_disable_irqs()? I don't see any when grepping.
> >
> > -Scott
>
> Will use hard_irq_disable().
>
> I think this is a general problem for powerpc.
> Should clear MSR_EE before suspend. I agree to put it
> in generic_suspend_disable_irqs().
BTW, make sure you test this patchset with CONFIG_DEBUG_PREEMPT and
similar debugging options to help ensure that the soft IRQ state is
being tracked properly.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit
2014-03-14 22:41 ` Scott Wood
@ 2014-03-17 9:37 ` Chenhui Zhao
0 siblings, 0 replies; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-17 9:37 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, Mar 14, 2014 at 05:41:41PM -0500, Scott Wood wrote:
> On Wed, 2014-03-12 at 15:46 +0800, Chenhui Zhao wrote:
> > On Tue, Mar 11, 2014 at 06:51:20PM -0500, Scott Wood wrote:
> > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > In 64-bit mode, kernel just clears the irq soft-enable flag
> > > > in struct paca_struct to disable external irqs. But, in
> > > > the case of suspend, irqs should be disabled by hardware.
> > > > Therefore, hook a function to ppc_md.suspend_disable_irqs
> > > > to really disable irqs.
> > > >
> > > > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > > > ---
> > > > arch/powerpc/platforms/85xx/corenet_generic.c | 12 ++++++++++++
> > > > 1 files changed, 12 insertions(+), 0 deletions(-)
> > > >
> > > > diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c
> > > > index 3fdf9f3..983d81f 100644
> > > > --- a/arch/powerpc/platforms/85xx/corenet_generic.c
> > > > +++ b/arch/powerpc/platforms/85xx/corenet_generic.c
> > > > @@ -32,6 +32,13 @@
> > > > #include <sysdev/fsl_pci.h>
> > > > #include "smp.h"
> > > >
> > > > +#if defined(CONFIG_PPC64) && defined(CONFIG_SUSPEND)
> > > > +static void fsl_suspend_disable_irqs(void)
> > > > +{
> > > > + __hard_irq_disable();
> > > > +}
> > > > +#endif
> > >
> > > Why the underscore version? Don't you want PACA_IRQ_HARD_DIS to be set?
> > >
> > > If hard disabling is appropriate here, shouldn't we do it in
> > > generic_suspend_disable_irqs()?
> > >
> > > Are there any existing platforms that supply a
> > > ppc_md.suspend_disable_irqs()? I don't see any when grepping.
> > >
> > > -Scott
> >
> > Will use hard_irq_disable().
> >
> > I think this is a general problem for powerpc.
> > Should clear MSR_EE before suspend. I agree to put it
> > in generic_suspend_disable_irqs().
>
> BTW, make sure you test this patchset with CONFIG_DEBUG_PREEMPT and
> similar debugging options to help ensure that the soft IRQ state is
> being tracked properly.
>
> -Scott
OK. I'll keep that in mind.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
` (3 preceding siblings ...)
2014-03-07 4:58 ` [PATCH 5/9] powerpc/85xx: disable irq by hardware when suspend for 64-bit Chenhui Zhao
@ 2014-03-07 4:58 ` Chenhui Zhao
2014-03-12 0:00 ` Scott Wood
2014-03-07 4:58 ` [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep Chenhui Zhao
` (2 subsequent siblings)
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
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@freescale.com>
---
arch/powerpc/Kconfig | 4 +-
arch/powerpc/platforms/85xx/Makefile | 3 +
arch/powerpc/platforms/85xx/qoriq_pm.c | 78 ++++++++++++++++++++++++++++++++
3 files changed, 83 insertions(+), 2 deletions(-)
create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 05f6323..e1d6510 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -222,7 +222,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
@@ -709,7 +709,7 @@ config FSL_PCI
config FSL_PMC
bool
default y
- depends on SUSPEND && (PPC_85xx || PPC_86xx)
+ depends on SUSPEND && (PPC_85xx && !PPC_E500MC || PPC_86xx)
help
Freescale MPC85xx/MPC86xx power management controller support
(suspend/resume). For MPC83xx see platforms/83xx/suspend.c
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 25cebe7..7fae817 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -2,6 +2,9 @@
# Makefile for the PowerPC 85xx linux kernel.
#
obj-$(CONFIG_SMP) += smp.o
+ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
+obj-$(CONFIG_SUSPEND) += qoriq_pm.o
+endif
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..915b13b
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -0,0 +1,78 @@
+/*
+ * Support Power Management feature
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.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 <sysdev/fsl_soc.h>
+
+#define FSL_SLEEP 0x1
+#define FSL_DEEP_SLEEP 0x2
+
+/* specify the sleep state of the present platform */
+int sleep_pm_state;
+/* supported sleep modes by the present platform */
+static unsigned int sleep_modes;
+
+static int qoriq_suspend_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+
+ if (cur_cpu_spec->cpu_flush_caches)
+ cur_cpu_spec->cpu_flush_caches();
+
+ ret = qoriq_pm_ops->plat_enter_state(sleep_pm_state);
+
+ break;
+
+ default:
+ ret = -EINVAL;
+
+ }
+
+ return ret;
+}
+
+static int qoriq_suspend_valid(suspend_state_t state)
+{
+ if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_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)
+{
+ struct device_node *np;
+
+ sleep_modes = FSL_SLEEP;
+ sleep_pm_state = PLAT_PM_SLEEP;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
+ if (np)
+ sleep_pm_state = PLAT_PM_LPM20;
+
+ suspend_set_ops(&qoriq_suspend_ops);
+
+ return 0;
+}
+arch_initcall(qoriq_suspend_init);
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
2014-03-07 4:58 ` [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM Chenhui Zhao
@ 2014-03-12 0:00 ` Scott Wood
2014-03-12 8:08 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-12 0:00 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> 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@freescale.com>
> ---
> arch/powerpc/Kconfig | 4 +-
> arch/powerpc/platforms/85xx/Makefile | 3 +
> arch/powerpc/platforms/85xx/qoriq_pm.c | 78 ++++++++++++++++++++++++++++++++
> 3 files changed, 83 insertions(+), 2 deletions(-)
> create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 05f6323..e1d6510 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -222,7 +222,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
> @@ -709,7 +709,7 @@ config FSL_PCI
> config FSL_PMC
> bool
> default y
> - depends on SUSPEND && (PPC_85xx || PPC_86xx)
> + depends on SUSPEND && (PPC_85xx && !PPC_E500MC || PPC_86xx)
Don't mix && and || without parentheses.
Maybe convert this into being selected (similar to FSL_RCPM), rather
than default y?
> diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> index 25cebe7..7fae817 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -2,6 +2,9 @@
> # Makefile for the PowerPC 85xx linux kernel.
> #
> obj-$(CONFIG_SMP) += smp.o
> +ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
> +obj-$(CONFIG_SUSPEND) += qoriq_pm.o
> +endif
There should probably be a kconfig symbol for this.
> diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
> new file mode 100644
> index 0000000..915b13b
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
> @@ -0,0 +1,78 @@
> +/*
> + * Support Power Management feature
> + *
> + * Copyright 2014 Freescale Semiconductor Inc.
> + *
> + * Author: Chenhui Zhao <chenhui.zhao@freescale.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 <sysdev/fsl_soc.h>
> +
> +#define FSL_SLEEP 0x1
> +#define FSL_DEEP_SLEEP 0x2
FSL_DEEP_SLEEP is unused.
> +
> +/* specify the sleep state of the present platform */
> +int sleep_pm_state;
> +/* supported sleep modes by the present platform */
> +static unsigned int sleep_modes;
Why is one signed and the other unsigned?
> +
> +static int qoriq_suspend_enter(suspend_state_t state)
> +{
> + int ret = 0;
> +
> + switch (state) {
> + case PM_SUSPEND_STANDBY:
> +
> + if (cur_cpu_spec->cpu_flush_caches)
> + cur_cpu_spec->cpu_flush_caches();
> +
> + ret = qoriq_pm_ops->plat_enter_state(sleep_pm_state);
> +
> + break;
> +
> + default:
> + ret = -EINVAL;
> +
> + }
> +
> + return ret;
> +}
> +
> +static int qoriq_suspend_valid(suspend_state_t state)
> +{
> + if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_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)
> +{
> + struct device_node *np;
> +
> + sleep_modes = FSL_SLEEP;
> + sleep_pm_state = PLAT_PM_SLEEP;
> +
> + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
> + if (np)
> + sleep_pm_state = PLAT_PM_LPM20;
> +
> + suspend_set_ops(&qoriq_suspend_ops);
> +
> + return 0;
> +}
> +arch_initcall(qoriq_suspend_init);
Why is this not a platform driver? If fsl_pmc can do it...
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
2014-03-12 0:00 ` Scott Wood
@ 2014-03-12 8:08 ` Chenhui Zhao
2014-03-14 22:46 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 8:08 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 11, 2014 at 07:00:27PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > 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@freescale.com>
> > ---
> > arch/powerpc/Kconfig | 4 +-
> > arch/powerpc/platforms/85xx/Makefile | 3 +
> > arch/powerpc/platforms/85xx/qoriq_pm.c | 78 ++++++++++++++++++++++++++++++++
> > 3 files changed, 83 insertions(+), 2 deletions(-)
> > create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c
> >
> > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> > index 05f6323..e1d6510 100644
> > --- a/arch/powerpc/Kconfig
> > +++ b/arch/powerpc/Kconfig
> > @@ -222,7 +222,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
> > @@ -709,7 +709,7 @@ config FSL_PCI
> > config FSL_PMC
> > bool
> > default y
> > - depends on SUSPEND && (PPC_85xx || PPC_86xx)
> > + depends on SUSPEND && (PPC_85xx && !PPC_E500MC || PPC_86xx)
>
> Don't mix && and || without parentheses.
>
> Maybe convert this into being selected (similar to FSL_RCPM), rather
> than default y?
Yes, will do.
>
> > diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> > index 25cebe7..7fae817 100644
> > --- a/arch/powerpc/platforms/85xx/Makefile
> > +++ b/arch/powerpc/platforms/85xx/Makefile
> > @@ -2,6 +2,9 @@
> > # Makefile for the PowerPC 85xx linux kernel.
> > #
> > obj-$(CONFIG_SMP) += smp.o
> > +ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
> > +obj-$(CONFIG_SUSPEND) += qoriq_pm.o
> > +endif
>
> There should probably be a kconfig symbol for this.
OK.
>
> > diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
> > new file mode 100644
> > index 0000000..915b13b
> > --- /dev/null
> > +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
> > @@ -0,0 +1,78 @@
> > +/*
> > + * Support Power Management feature
> > + *
> > + * Copyright 2014 Freescale Semiconductor Inc.
> > + *
> > + * Author: Chenhui Zhao <chenhui.zhao@freescale.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 <sysdev/fsl_soc.h>
> > +
> > +#define FSL_SLEEP 0x1
> > +#define FSL_DEEP_SLEEP 0x2
>
> FSL_DEEP_SLEEP is unused.
Will be used in the last patch.
[PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
>
> > +
> > +/* specify the sleep state of the present platform */
> > +int sleep_pm_state;
> > +/* supported sleep modes by the present platform */
> > +static unsigned int sleep_modes;
>
> Why is one signed and the other unsigned?
Undesigned. Will change them all to unsigned.
>
> > +
> > +static int qoriq_suspend_enter(suspend_state_t state)
> > +{
> > + int ret = 0;
> > +
> > + switch (state) {
> > + case PM_SUSPEND_STANDBY:
> > +
> > + if (cur_cpu_spec->cpu_flush_caches)
> > + cur_cpu_spec->cpu_flush_caches();
> > +
> > + ret = qoriq_pm_ops->plat_enter_state(sleep_pm_state);
> > +
> > + break;
> > +
> > + default:
> > + ret = -EINVAL;
> > +
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int qoriq_suspend_valid(suspend_state_t state)
> > +{
> > + if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_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)
> > +{
> > + struct device_node *np;
> > +
> > + sleep_modes = FSL_SLEEP;
> > + sleep_pm_state = PLAT_PM_SLEEP;
> > +
> > + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
> > + if (np)
> > + sleep_pm_state = PLAT_PM_LPM20;
> > +
> > + suspend_set_ops(&qoriq_suspend_ops);
> > +
> > + return 0;
> > +}
> > +arch_initcall(qoriq_suspend_init);
>
> Why is this not a platform driver? If fsl_pmc can do it...
>
> -Scott
It can be, but what advantage of being a platform driver.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
2014-03-12 8:08 ` Chenhui Zhao
@ 2014-03-14 22:46 ` Scott Wood
0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2014-03-14 22:46 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Wed, 2014-03-12 at 16:08 +0800, Chenhui Zhao wrote:
> On Tue, Mar 11, 2014 at 07:00:27PM -0500, Scott Wood wrote:
> > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > 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@freescale.com>
> > > ---
> > > arch/powerpc/Kconfig | 4 +-
> > > arch/powerpc/platforms/85xx/Makefile | 3 +
> > > arch/powerpc/platforms/85xx/qoriq_pm.c | 78 ++++++++++++++++++++++++++++++++
> > > 3 files changed, 83 insertions(+), 2 deletions(-)
> > > create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c
> > >
> > > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> > > index 05f6323..e1d6510 100644
> > > --- a/arch/powerpc/Kconfig
> > > +++ b/arch/powerpc/Kconfig
> > > @@ -222,7 +222,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
> > > @@ -709,7 +709,7 @@ config FSL_PCI
> > > config FSL_PMC
> > > bool
> > > default y
> > > - depends on SUSPEND && (PPC_85xx || PPC_86xx)
> > > + depends on SUSPEND && (PPC_85xx && !PPC_E500MC || PPC_86xx)
> >
> > Don't mix && and || without parentheses.
> >
> > Maybe convert this into being selected (similar to FSL_RCPM), rather
> > than default y?
>
> Yes, will do.
>
> >
> > > diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> > > index 25cebe7..7fae817 100644
> > > --- a/arch/powerpc/platforms/85xx/Makefile
> > > +++ b/arch/powerpc/platforms/85xx/Makefile
> > > @@ -2,6 +2,9 @@
> > > # Makefile for the PowerPC 85xx linux kernel.
> > > #
> > > obj-$(CONFIG_SMP) += smp.o
> > > +ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
> > > +obj-$(CONFIG_SUSPEND) += qoriq_pm.o
> > > +endif
> >
> > There should probably be a kconfig symbol for this.
>
> OK.
>
> >
> > > diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
> > > new file mode 100644
> > > index 0000000..915b13b
> > > --- /dev/null
> > > +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
> > > @@ -0,0 +1,78 @@
> > > +/*
> > > + * Support Power Management feature
> > > + *
> > > + * Copyright 2014 Freescale Semiconductor Inc.
> > > + *
> > > + * Author: Chenhui Zhao <chenhui.zhao@freescale.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 <sysdev/fsl_soc.h>
> > > +
> > > +#define FSL_SLEEP 0x1
> > > +#define FSL_DEEP_SLEEP 0x2
> >
> > FSL_DEEP_SLEEP is unused.
>
> Will be used in the last patch.
> [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
Ideally the #define would have been introduced in that patch.
> > > + sleep_modes = FSL_SLEEP;
> > > + sleep_pm_state = PLAT_PM_SLEEP;
> > > +
> > > + np = of_find_compatible_node(NULL, NULL, "fsl,qoriq-rcpm-2.0");
> > > + if (np)
> > > + sleep_pm_state = PLAT_PM_LPM20;
> > > +
> > > + suspend_set_ops(&qoriq_suspend_ops);
> > > +
> > > + return 0;
> > > +}
> > > +arch_initcall(qoriq_suspend_init);
> >
> > Why is this not a platform driver? If fsl_pmc can do it...
> >
> > -Scott
>
> It can be, but what advantage of being a platform driver.
If nothing else, compliance with the standard way of doing things. Why
not make it a platform driver? You'd be able to use dev_err, have a
place in sysfs if attributes are needed in the future, etc.
A better answer might be that there are multiple not-very-related files
driving different portions of RCPM.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
` (4 preceding siblings ...)
2014-03-07 4:58 ` [PATCH 6/9] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM Chenhui Zhao
@ 2014-03-07 4:58 ` Chenhui Zhao
2014-03-12 0:08 ` Scott Wood
2014-03-07 4:58 ` [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers Chenhui Zhao
2014-03-07 4:58 ` [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040 Chenhui Zhao
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
From: Hongbo Zhang <hongbo.zhang@freescale.com>
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@freescale.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
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;
=20
extern int fsl_rcpm_init(void);
=20
+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
=20
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) +=3D x86/
obj-$(CONFIG_OLPC) +=3D olpc/
obj-$(CONFIG_GOLDFISH) +=3D goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) +=3D chrome/
+obj-$(CONFIG_FSL_SOC) +=3D 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 enter=
ing deep
+ sleep, and also wakes up system when a wake up event happens.
diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefil=
e
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) +=3D sleep_fsm.o
diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/slee=
p_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@freescale.com>
+ * Chenhui Zhao <chenhui.zhao@freescale.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 y=
our
+ * 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 =3D dcsr_base;
+
+ /* Disable All SCU Actions */
+ for (offset =3D EPACR0; offset <=3D EPACR15; offset +=3D FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPEVTCRn */
+ for (offset =3D EPEVTCR0; offset <=3D EPEVTCR9; offset +=3D FSL_STRIDE_=
4B)
+ epu_write(offset, 0);
+
+ /* Clear Event Processor Global Control Register */
+ epu_write(EPGCR, 0);
+
+ /* Clear EPSMCRn */
+ for (offset =3D EPSMCR0; offset <=3D EPSMCR15; offset +=3D FSL_STRIDE_8=
B)
+ epu_write(offset, 0);
+
+ /* Clear EPCCRn */
+ for (offset =3D EPCCR0; offset <=3D EPCCR15; offset +=3D FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPCMPRn */
+ for (offset =3D EPCMPR0; offset <=3D EPCMPR15; offset +=3D FSL_STRIDE_4=
B)
+ 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 =3D EPCTR0; offset <=3D EPCTR31; offset +=3D FSL_STRIDE_4B)
+ epu_write(offset, 0);
+
+ /* Clear EPIMCRn */
+ for (offset =3D EPIMCR0; offset <=3D EPIMCR31; offset +=3D FSL_STRIDE_4=
B)
+ epu_write(offset, 0);
+
+ /* Clear EPXTRIGCRn */
+ epu_write(EPXTRIGCR, 0);
+
+ /* Disable all SCUs EPECRn */
+ for (offset =3D EPECR0; offset <=3D EPECR15; offset +=3D 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=E2=80=99s 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);
+
+}
--=20
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-07 4:58 ` [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep Chenhui Zhao
@ 2014-03-12 0:08 ` Scott Wood
2014-03-12 8:34 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-12 0:08 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>
> 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@freescale.com>
> Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
Couldn't this be part of qoriq_pm.c?
> 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);
__iomem
> +
> #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
Chrome doesn't need an ifdef -- why does this?
> 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
Why is this here while the other stuff is in arch/powerpc/sysdev?
> +/* Block offsets */
> +#define RCPM_BLOCK_OFFSET 0x00022000
> +#define EPU_BLOCK_OFFSET 0x00000000
> +#define NPC_BLOCK_OFFSET 0x00001000
Why don't these block offsets come from the device tree?
> +static void *g_dcsr_base;
__iomem
> + /* 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);
Where do these magic numbers come from? Which chips are they valid for?
> +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);
> +
> +}
Don't put blank lines at the beginning/end of a block.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-12 0:08 ` Scott Wood
@ 2014-03-12 8:34 ` Chenhui Zhao
2014-03-14 22:51 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 8:34 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 11, 2014 at 07:08:43PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > From: Hongbo Zhang <hongbo.zhang@freescale.com>
> >
> > 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@freescale.com>
> > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
>
> Couldn't this be part of qoriq_pm.c?
Put the code in drivers/platform/fsl/ so that LS1 can share these code.
>
> > 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);
>
> __iomem
Thanks. Will add.
>
> > +
> > #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
>
> Chrome doesn't need an ifdef -- why does this?
Don't wish other platform see these options, and the X86 and GOLDFISH have
ifdefs.
>
> > 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
>
> Why is this here while the other stuff is in arch/powerpc/sysdev?
>
> > +/* Block offsets */
> > +#define RCPM_BLOCK_OFFSET 0x00022000
> > +#define EPU_BLOCK_OFFSET 0x00000000
> > +#define NPC_BLOCK_OFFSET 0x00001000
>
> Why don't these block offsets come from the device tree?
Have maped DCSR registers. Don't wish to remap them.
>
> > +static void *g_dcsr_base;
>
> __iomem
OK.
>
> > + /* 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);
>
> Where do these magic numbers come from? Which chips are they valid for?
They are for T1040. Can be found in the RCPM chapter of T1040RM.
>
> > +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);
> > +
> > +}
>
> Don't put blank lines at the beginning/end of a block.
>
> -Scott
Thanks.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-12 8:34 ` Chenhui Zhao
@ 2014-03-14 22:51 ` Scott Wood
2014-03-17 10:27 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-14 22:51 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Wed, 2014-03-12 at 16:34 +0800, Chenhui Zhao wrote:
> On Tue, Mar 11, 2014 at 07:08:43PM -0500, Scott Wood wrote:
> > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > From: Hongbo Zhang <hongbo.zhang@freescale.com>
> > >
> > > 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@freescale.com>
> > > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> >
> > Couldn't this be part of qoriq_pm.c?
>
> Put the code in drivers/platform/fsl/ so that LS1 can share these code.
How can LS1 share it if it's got hardcoded T1040 values?
> > > 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
> >
> > Chrome doesn't need an ifdef -- why does this?
>
> Don't wish other platform see these options, and the X86 and GOLDFISH have
> ifdefs.
The point is you can implement the dependency inside
drivers/platform/fsl/Kconfig.
> > > 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
> >
> > Why is this here while the other stuff is in arch/powerpc/sysdev?
> >
> > > +/* Block offsets */
> > > +#define RCPM_BLOCK_OFFSET 0x00022000
> > > +#define EPU_BLOCK_OFFSET 0x00000000
> > > +#define NPC_BLOCK_OFFSET 0x00001000
> >
> > Why don't these block offsets come from the device tree?
>
> Have maped DCSR registers. Don't wish to remap them.
We don't wish to have hardcoded CCSR/DCSR offsets in the kernel source.
Sorry.
> > > + /* 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);
> >
> > Where do these magic numbers come from? Which chips are they valid for?
>
> They are for T1040. Can be found in the RCPM chapter of T1040RM.
Then put in a comment to that effect, including what part of the RCPM
chapter.
How do you plan to handle the addition of another SoC with different
values?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-14 22:51 ` Scott Wood
@ 2014-03-17 10:27 ` Chenhui Zhao
2014-03-18 23:21 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-17 10:27 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, Mar 14, 2014 at 05:51:09PM -0500, Scott Wood wrote:
> On Wed, 2014-03-12 at 16:34 +0800, Chenhui Zhao wrote:
> > On Tue, Mar 11, 2014 at 07:08:43PM -0500, Scott Wood wrote:
> > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > From: Hongbo Zhang <hongbo.zhang@freescale.com>
> > > >
> > > > 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@freescale.com>
> > > > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > >
> > > Couldn't this be part of qoriq_pm.c?
> >
> > Put the code in drivers/platform/fsl/ so that LS1 can share these code.
>
> How can LS1 share it if it's got hardcoded T1040 values?
>
> > > > 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
> > >
> > > Chrome doesn't need an ifdef -- why does this?
> >
> > Don't wish other platform see these options, and the X86 and GOLDFISH have
> > ifdefs.
>
> The point is you can implement the dependency inside
> drivers/platform/fsl/Kconfig.
OK.
>
> > > > 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
> > >
> > > Why is this here while the other stuff is in arch/powerpc/sysdev?
> > >
> > > > +/* Block offsets */
> > > > +#define RCPM_BLOCK_OFFSET 0x00022000
> > > > +#define EPU_BLOCK_OFFSET 0x00000000
> > > > +#define NPC_BLOCK_OFFSET 0x00001000
> > >
> > > Why don't these block offsets come from the device tree?
> >
> > Have maped DCSR registers. Don't wish to remap them.
>
> We don't wish to have hardcoded CCSR/DCSR offsets in the kernel source.
> Sorry.
OK.
>
> > > > + /* 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);
> > >
> > > Where do these magic numbers come from? Which chips are they valid for?
> >
> > They are for T1040. Can be found in the RCPM chapter of T1040RM.
>
> Then put in a comment to that effect, including what part of the RCPM
> chapter.
>
> How do you plan to handle the addition of another SoC with different
> values?
>
> -Scott
Had thought that using an array to put these values (pairs of offset and value)
and passing the array to the function.
However, luckily T104x and LS1 have same values for these registers
according to the current Reference Manuals.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-17 10:27 ` Chenhui Zhao
@ 2014-03-18 23:21 ` Scott Wood
2014-03-19 0:08 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-18 23:21 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Mon, 2014-03-17 at 18:27 +0800, Chenhui Zhao wrote:
> On Fri, Mar 14, 2014 at 05:51:09PM -0500, Scott Wood wrote:
> > On Wed, 2014-03-12 at 16:34 +0800, Chenhui Zhao wrote:
> > > On Tue, Mar 11, 2014 at 07:08:43PM -0500, Scott Wood wrote:
> > > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > > + /* 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);
> > > >
> > > > Where do these magic numbers come from? Which chips are they valid for?
> > >
> > > They are for T1040. Can be found in the RCPM chapter of T1040RM.
> >
> > Then put in a comment to that effect, including what part of the RCPM
> > chapter.
> >
> > How do you plan to handle the addition of another SoC with different
> > values?
> >
> > -Scott
>
> Had thought that using an array to put these values (pairs of offset and value)
> and passing the array to the function.
Arrays are better than a long sequence of function calls in any case.
> However, luckily T104x and LS1 have same values for these registers
> according to the current Reference Manuals.
If it's likely that the values will remain the same on all chips for the
near future, then a fancy mechanism to select the array to use can wait
-- but you should still use an array, and have a comment acknowledging
the possibility of needing to accommodate different values in the
future.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep
2014-03-18 23:21 ` Scott Wood
@ 2014-03-19 0:08 ` Chenhui Zhao
0 siblings, 0 replies; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-19 0:08 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 18, 2014 at 06:21:22PM -0500, Scott Wood wrote:
> On Mon, 2014-03-17 at 18:27 +0800, Chenhui Zhao wrote:
> > On Fri, Mar 14, 2014 at 05:51:09PM -0500, Scott Wood wrote:
> > > On Wed, 2014-03-12 at 16:34 +0800, Chenhui Zhao wrote:
> > > > On Tue, Mar 11, 2014 at 07:08:43PM -0500, Scott Wood wrote:
> > > > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > > > + /* 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);
> > > > >
> > > > > Where do these magic numbers come from? Which chips are they valid for?
> > > >
> > > > They are for T1040. Can be found in the RCPM chapter of T1040RM.
> > >
> > > Then put in a comment to that effect, including what part of the RCPM
> > > chapter.
> > >
> > > How do you plan to handle the addition of another SoC with different
> > > values?
> > >
> > > -Scott
> >
> > Had thought that using an array to put these values (pairs of offset and value)
> > and passing the array to the function.
>
> Arrays are better than a long sequence of function calls in any case.
>
> > However, luckily T104x and LS1 have same values for these registers
> > according to the current Reference Manuals.
>
> If it's likely that the values will remain the same on all chips for the
> near future, then a fancy mechanism to select the array to use can wait
> -- but you should still use an array, and have a comment acknowledging
> the possibility of needing to accommodate different values in the
> future.
>
> -Scott
OK. Will use an array to pass the values.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
` (5 preceding siblings ...)
2014-03-07 4:58 ` [PATCH 7/9] fsl: add EPU FSM configuration for deep sleep Chenhui Zhao
@ 2014-03-07 4:58 ` Chenhui Zhao
2014-03-12 0:45 ` Scott Wood
2014-03-07 4:58 ` [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040 Chenhui Zhao
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
From: Wang Dongsheng <dongsheng.wang@freescale.com>
Add booke_cpu_state_save() and booke_cpu_state_restore() functions which can be
used to save/restore CPU's registers in the case of deep sleep and hibernation.
Supported processors: E6500, E5500, E500MC, E500v2 and E500v1.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
---
arch/powerpc/include/asm/booke_save_regs.h | 96 ++++++++
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/booke_save_regs.S | 361 ++++++++++++++++++++++++++++
3 files changed, 458 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/include/asm/booke_save_regs.h
create mode 100644 arch/powerpc/kernel/booke_save_regs.S
diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
new file mode 100644
index 0000000..87c357a
--- /dev/null
+++ b/arch/powerpc/include/asm/booke_save_regs.h
@@ -0,0 +1,96 @@
+/*
+ * Save/restore e500 series core registers
+ *
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_FSL_SLEEP_H
+#define __ASM_FSL_SLEEP_H
+
+/*
+ * 8 bytes for each register, which is compatible with
+ * both 32-bit and 64-bit registers
+ *
+ * Acronyms:
+ * dw(data width) 0x08
+ *
+ * Map:
+ * General-Purpose Registers
+ * GPR1(sp) 0
+ * GPR2 0x8 (dw * 1)
+ * GPR13 - GPR31 0x10 ~ 0xa0 (dw * 2 ~ dw * 20)
+ * Foating-point registers
+ * FPR14 - FPR31 0xa8 ~ 0x130 (dw * 21 ~ dw * 38)
+ * Registers for Branch Operations
+ * CR 0x138 (dw * 39)
+ * LR 0x140 (dw * 40)
+ * Processor Control Registers
+ * MSR 0x148 (dw * 41)
+ * EPCR 0x150 (dw * 42)
+ *
+ * Only e500, e500v2 need to save HID0 - HID1
+ * HID0 - HID1 0x158 ~ 0x160 (dw * 43 ~ dw * 44)
+ * Timer Registers
+ * TCR 0x168 (dw * 45)
+ * TB(64bit) 0x170 (dw * 46)
+ * TBU(32bit) 0x178 (dw * 47)
+ * TBL(32bit) 0x180 (dw * 48)
+ * Interrupt Registers
+ * IVPR 0x188 (dw * 49)
+ * IVOR0 - IVOR15 0x190 ~ 0x208 (dw * 50 ~ dw * 65)
+ * IVOR32 - IVOR41 0x210 ~ 0x258 (dw * 66 ~ dw * 75)
+ * Software-Use Registers
+ * SPRG1 0x260 (dw * 76), 64-bit need to save.
+ * SPRG3 0x268 (dw * 77), 32-bit need to save.
+ * MMU Registers
+ * PID0 - PID2 0x270 ~ 0x280 (dw * 78 ~ dw * 80)
+ * Debug Registers
+ * DBCR0 - DBCR2 0x288 ~ 0x298 (dw * 81 ~ dw * 83)
+ * IAC1 - IAC4 0x2a0 ~ 0x2b8 (dw * 84 ~ dw * 87)
+ * DAC1 - DAC2 0x2c0 ~ 0x2c8 (dw * 88 ~ dw * 89)
+ *
+ */
+
+#define SR_GPR1 0x000
+#define SR_GPR2 0x008
+#define SR_GPR13 0x010
+#define SR_FPR14 0x0a8
+#define SR_CR 0x138
+#define SR_LR 0x140
+#define SR_MSR 0x148
+#define SR_EPCR 0x150
+#define SR_HID0 0x158
+#define SR_TCR 0x168
+#define SR_TB 0x170
+#define SR_TBU 0x178
+#define SR_TBL 0x180
+#define SR_IVPR 0x188
+#define SR_IVOR0 0x190
+#define SR_IVOR32 0x210
+#define SR_SPRG1 0x260
+#define SR_SPRG3 0x268
+#define SR_PID0 0x270
+#define SR_DBCR0 0x288
+#define SR_IAC1 0x2a0
+#define SR_DAC1 0x2c0
+#define REGS_BUFFER_SIZE (SR_DAC1 + 0x10)
+
+/*
+ * hibernation and deepsleep save/restore different number of registers,
+ * use these flags to indicate.
+ */
+#define HIBERNATION_FLAG 1
+#define DEEPSLEEP_FLAG 2
+
+#ifndef __ASSEMBLY__
+extern void booke_cpu_state_save(void *buf, int type);
+extern void *booke_cpu_state_restore(void *buf, int type);
+#endif
+#endif
+
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index fcc9a89..64acae6 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_HIBERNATION) += swsusp_booke.o
else
obj-$(CONFIG_HIBERNATION) += swsusp_$(CONFIG_WORD_SIZE).o
endif
+obj-$(CONFIG_E500) += booke_save_regs.o
obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o
obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_44x) += cpu_setup_44x.o
diff --git a/arch/powerpc/kernel/booke_save_regs.S b/arch/powerpc/kernel/booke_save_regs.S
new file mode 100644
index 0000000..9ccd576
--- /dev/null
+++ b/arch/powerpc/kernel/booke_save_regs.S
@@ -0,0 +1,361 @@
+/*
+ * Freescale Power Management, Save/Restore core state
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Wang Dongsheng <dongsheng.wang@freescale.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 <asm/ppc_asm.h>
+#include <asm/booke_save_regs.h>
+
+/*
+ * Supported Core List:
+ * E500v1, E500v2, E500MC, E5500, E6500.
+ */
+
+/* Save/Restore register operation define */
+#define do_save_gpr_reg(reg, addr) \
+ PPC_STL reg, addr(r10)
+
+#define do_save_fpr_reg(reg, addr) \
+ stfd reg, addr(r10)
+
+#define do_save_spr_reg(reg, addr) \
+ mfspr r0, SPRN_##reg ;\
+ PPC_STL r0, addr(r10)
+
+#define do_save_special_reg(special, addr) \
+ mf##special r0 ;\
+ PPC_STL r0, addr(r10)
+
+#define do_restore_gpr_reg(reg, addr) \
+ PPC_LL reg, addr(r10)
+
+#define do_restore_fpr_reg(reg, addr) \
+ lfd reg, addr(r10)
+
+#define do_restore_spr_reg(reg, addr) \
+ PPC_LL r0, addr(r10) ;\
+ mtspr SPRN_##reg, r0
+
+#define do_restore_special_reg(special, addr) \
+ PPC_LL r0, addr(r10) ;\
+ mt##special r0
+
+#define do_sr_general_gpr_regs(func) \
+ do_##func##_gpr_reg(r1, SR_GPR1) ;\
+ do_##func##_gpr_reg(r2, SR_GPR2) ;\
+ do_##func##_gpr_reg(r13, SR_GPR13 + 0x00) ;\
+ do_##func##_gpr_reg(r14, SR_GPR13 + 0x08) ;\
+ do_##func##_gpr_reg(r15, SR_GPR13 + 0x10) ;\
+ do_##func##_gpr_reg(r16, SR_GPR13 + 0x18) ;\
+ do_##func##_gpr_reg(r17, SR_GPR13 + 0x20) ;\
+ do_##func##_gpr_reg(r18, SR_GPR13 + 0x28) ;\
+ do_##func##_gpr_reg(r19, SR_GPR13 + 0x30) ;\
+ do_##func##_gpr_reg(r20, SR_GPR13 + 0x38) ;\
+ do_##func##_gpr_reg(r21, SR_GPR13 + 0x40) ;\
+ do_##func##_gpr_reg(r22, SR_GPR13 + 0x48) ;\
+ do_##func##_gpr_reg(r23, SR_GPR13 + 0x50) ;\
+ do_##func##_gpr_reg(r24, SR_GPR13 + 0x58) ;\
+ do_##func##_gpr_reg(r25, SR_GPR13 + 0x60) ;\
+ do_##func##_gpr_reg(r26, SR_GPR13 + 0x68) ;\
+ do_##func##_gpr_reg(r27, SR_GPR13 + 0x70) ;\
+ do_##func##_gpr_reg(r28, SR_GPR13 + 0x78) ;\
+ do_##func##_gpr_reg(r29, SR_GPR13 + 0x80) ;\
+ do_##func##_gpr_reg(r30, SR_GPR13 + 0x88) ;\
+ do_##func##_gpr_reg(r31, SR_GPR13 + 0x90)
+
+#define do_sr_general_pcr_regs(func) \
+ do_##func##_spr_reg(EPCR, SR_EPCR) ;\
+ do_##func##_spr_reg(HID0, SR_HID0 + 0x00)
+
+#define do_sr_e500_pcr_regs(func) \
+ do_##func##_spr_reg(HID1, SR_HID0 + 0x08)
+
+#define do_sr_save_tb_regs \
+ do_save_spr_reg(TBRU, SR_TBU) ;\
+ do_save_spr_reg(TBRL, SR_TBL)
+
+#define do_sr_restore_tb_regs \
+ do_restore_spr_reg(TBWU, SR_TBU) ;\
+ do_restore_spr_reg(TBWL, SR_TBL)
+
+#define do_sr_general_time_regs(func) \
+ do_sr_##func##_tb_regs ;\
+ do_##func##_spr_reg(TCR, SR_TCR)
+
+#define do_sr_interrupt_regs(func) \
+ do_##func##_spr_reg(IVPR, SR_IVPR) ;\
+ do_##func##_spr_reg(IVOR0, SR_IVOR0 + 0x00) ;\
+ do_##func##_spr_reg(IVOR1, SR_IVOR0 + 0x08) ;\
+ do_##func##_spr_reg(IVOR2, SR_IVOR0 + 0x10) ;\
+ do_##func##_spr_reg(IVOR3, SR_IVOR0 + 0x18) ;\
+ do_##func##_spr_reg(IVOR4, SR_IVOR0 + 0x20) ;\
+ do_##func##_spr_reg(IVOR5, SR_IVOR0 + 0x28) ;\
+ do_##func##_spr_reg(IVOR6, SR_IVOR0 + 0x30) ;\
+ do_##func##_spr_reg(IVOR7, SR_IVOR0 + 0x38) ;\
+ do_##func##_spr_reg(IVOR8, SR_IVOR0 + 0x40) ;\
+ do_##func##_spr_reg(IVOR10, SR_IVOR0 + 0x50) ;\
+ do_##func##_spr_reg(IVOR11, SR_IVOR0 + 0x58) ;\
+ do_##func##_spr_reg(IVOR12, SR_IVOR0 + 0x60) ;\
+ do_##func##_spr_reg(IVOR13, SR_IVOR0 + 0x68) ;\
+ do_##func##_spr_reg(IVOR14, SR_IVOR0 + 0x70) ;\
+ do_##func##_spr_reg(IVOR15, SR_IVOR0 + 0x78)
+
+#define do_e500_sr_interrupt_regs(func) \
+ do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
+ do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
+ do_##func##_spr_reg(IVOR34, SR_IVOR32 + 0x10)
+
+#define do_e500mc_sr_interrupt_regs(func) \
+ do_##func##_spr_reg(IVOR9, SR_IVOR0 + 0x48) ;\
+ do_##func##_spr_reg(IVOR35, SR_IVOR32 + 0x18) ;\
+ do_##func##_spr_reg(IVOR36, SR_IVOR32 + 0x20) ;\
+ do_##func##_spr_reg(IVOR37, SR_IVOR32 + 0x28) ;\
+ do_##func##_spr_reg(IVOR38, SR_IVOR32 + 0x30) ;\
+ do_##func##_spr_reg(IVOR39, SR_IVOR32 + 0x38) ;\
+ do_##func##_spr_reg(IVOR40, SR_IVOR32 + 0x40) ;\
+ do_##func##_spr_reg(IVOR41, SR_IVOR32 + 0x48)
+
+#define do_e5500_sr_interrupt_regs(func) \
+ do_e500mc_sr_interrupt_regs(func)
+
+#define do_e6500_sr_interrupt_regs(func) \
+ do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
+ do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
+ do_e5500_sr_interrupt_regs(func)
+
+#define do_sr_general_software_regs(func) \
+ do_##func##_spr_reg(SPRG1, SR_SPRG1) ;\
+ do_##func##_spr_reg(SPRG3, SR_SPRG3) ;\
+ do_##func##_spr_reg(PID0, SR_PID0)
+
+#define do_sr_e500_mmu_regs(func) \
+ do_##func##_spr_reg(PID1, SR_PID0 + 0x08) ;\
+ do_##func##_spr_reg(PID2, SR_PID0 + 0x10)
+
+#define do_sr_debug_regs(func) \
+ do_##func##_spr_reg(DBCR0, SR_DBCR0 + 0x00) ;\
+ do_##func##_spr_reg(DBCR1, SR_DBCR0 + 0x08) ;\
+ do_##func##_spr_reg(DBCR2, SR_DBCR0 + 0x10) ;\
+ do_##func##_spr_reg(IAC1, SR_IAC1 + 0x00) ;\
+ do_##func##_spr_reg(IAC2, SR_IAC1 + 0x08) ;\
+ do_##func##_spr_reg(DAC1, SR_DAC1 + 0x00) ;\
+ do_##func##_spr_reg(DAC2, SR_DAC1 + 0x08)
+
+#define do_e6500_sr_debug_regs(func) \
+ do_##func##_spr_reg(IAC3, SR_IAC1 + 0x10) ;\
+ do_##func##_spr_reg(IAC4, SR_IAC1 + 0x18)
+
+ .section .text
+ .align 5
+booke_cpu_base_save:
+ do_sr_general_gpr_regs(save)
+ do_sr_general_pcr_regs(save)
+ do_sr_general_software_regs(save)
+1:
+ mfspr r5, SPRN_TBRU
+ do_sr_general_time_regs(save)
+ mfspr r6, SPRN_TBRU
+ cmpw r5, r6
+ bne 1b
+
+ blr
+
+booke_cpu_base_restore:
+ do_sr_general_gpr_regs(restore)
+ do_sr_general_pcr_regs(restore)
+ do_sr_general_software_regs(restore)
+
+ isync
+
+ /* Restore Time registers, clear tb lower to avoid wrap */
+ li r0, 0
+ mtspr SPRN_TBWL, r0
+ do_sr_general_time_regs(restore)
+
+ /* clear out status */
+ mfspr r0,SPRN_TSR
+ mtspr SPRN_TSR, r0
+
+ blr
+
+/* Base registers, e500v1, e500v2 need to do some special save/restore */
+e500_base_special_save:
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V1@l
+ cmpw r11, r12
+ beq 1f
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V2@l
+ cmpw r11, r12
+ bne 2f
+1:
+ do_sr_e500_pcr_regs(save)
+ do_sr_e500_mmu_regs(save)
+2:
+ blr
+
+e500_base_special_restore:
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V1@l
+ cmpw r11, r12
+ beq 1f
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V2@l
+ cmpw r11, r12
+ bne 2f
+1:
+ do_sr_e500_pcr_regs(save)
+ do_sr_e500_mmu_regs(save)
+2:
+ blr
+
+booke_cpu_append_save:
+ mfspr r0, SPRN_PVR
+ rlwinm r11, r0, 16, 16, 31
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E6500@l
+ cmpw r11, r12
+ beq e6500_append_save
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E5500@l
+ cmpw r11, r12
+ beq e5500_append_save
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500MC@l
+ cmpw r11, r12
+ beq e500mc_append_save
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V2@l
+ cmpw r11, r12
+ beq e500v2_append_save
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V1@l
+ cmpw r11, r12
+ beq e500v1_append_save
+ b 1f
+
+e6500_append_save:
+ do_e6500_sr_interrupt_regs(save)
+ do_e6500_sr_debug_regs(save)
+ b 1f
+
+e5500_append_save:
+ do_e5500_sr_interrupt_regs(save)
+ b 1f
+
+e500mc_append_save:
+ do_e500mc_sr_interrupt_regs(save)
+ b 1f
+
+e500v2_append_save:
+e500v1_append_save:
+ do_e500_sr_interrupt_regs(save)
+1:
+ do_sr_interrupt_regs(save)
+ do_sr_debug_regs(save)
+
+ blr
+
+booke_cpu_append_restore:
+ mfspr r0, SPRN_PVR
+ rlwinm r11, r0, 16, 16, 31
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E6500@l
+ cmpw r11, r12
+ beq e6500_append_restore
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E5500@l
+ cmpw r11, r12
+ beq e5500_append_restore
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500MC@l
+ cmpw r11, r12
+ beq e500mc_append_restore
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V2@l
+ cmpw r11, r12
+ beq e500v2_append_restore
+
+ lis r12, 0
+ ori r12, r12, PVR_VER_E500V1@l
+ cmpw r11, r12
+ beq e500v1_append_restore
+ b 1f
+
+e6500_append_restore:
+ do_e6500_sr_interrupt_regs(restore)
+ do_e6500_sr_debug_regs(restore)
+ b 1f
+
+e5500_append_restore:
+ do_e5500_sr_interrupt_regs(restore)
+ b 1f
+
+e500mc_append_restore:
+ do_e500mc_sr_interrupt_regs(restore)
+ b 1f
+
+e500v2_append_restore:
+e500v1_append_restore:
+ do_e500_sr_interrupt_regs(restore)
+1:
+ do_sr_interrupt_regs(restore)
+ do_sr_debug_regs(restore)
+ sync
+
+ blr
+
+/*
+ * r3 = the address of buffer
+ * r4 = type: HIBERNATION_FLAG or DEEPSLEEP_FLAG
+ */
+_GLOBAL(booke_cpu_state_save)
+ mflr r9
+ mr r10, r3
+
+ cmpwi r4, HIBERNATION_FLAG
+ beq 1f
+ bl booke_cpu_append_save
+1:
+ bl e500_base_special_save
+ bl booke_cpu_base_save
+
+ mtlr r9
+ blr
+
+/*
+ * r3 = the address of buffer
+ * r4 = type: HIBERNATION_FLAG or DEEPSLEEP_FLAG
+ */
+_GLOBAL(booke_cpu_state_restore)
+ mflr r9
+ mr r10, r3
+
+ cmpwi r4, HIBERNATION_FLAG
+ beq 1f
+
+ bl booke_cpu_append_restore
+1:
+ bl e500_base_special_restore
+ bl booke_cpu_base_restore
+
+ mtlr r9
+ blr
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers
2014-03-07 4:58 ` [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers Chenhui Zhao
@ 2014-03-12 0:45 ` Scott Wood
2014-03-12 9:42 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-12 0:45 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>
> Add booke_cpu_state_save() and booke_cpu_state_restore() functions which can be
> used to save/restore CPU's registers in the case of deep sleep and hibernation.
>
> Supported processors: E6500, E5500, E500MC, E500v2 and E500v1.
>
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> ---
> arch/powerpc/include/asm/booke_save_regs.h | 96 ++++++++
> arch/powerpc/kernel/Makefile | 1 +
> arch/powerpc/kernel/booke_save_regs.S | 361 ++++++++++++++++++++++++++++
> 3 files changed, 458 insertions(+), 0 deletions(-)
> create mode 100644 arch/powerpc/include/asm/booke_save_regs.h
> create mode 100644 arch/powerpc/kernel/booke_save_regs.S
>
> diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> new file mode 100644
> index 0000000..87c357a
> --- /dev/null
> +++ b/arch/powerpc/include/asm/booke_save_regs.h
> @@ -0,0 +1,96 @@
> +/*
> + * Save/restore e500 series core registers
Filename says booke, comment says e500.
Filename and comment also fail to point out that this is specifically
for standby/suspend, not for hibernate which is implemented in
swsusp_booke.S/swsusp_asm64.S.
> + *
> + * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
> + *
> + * Copyright 2014 Freescale Semiconductor Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __ASM_FSL_SLEEP_H
> +#define __ASM_FSL_SLEEP_H
> +
> +/*
> + * 8 bytes for each register, which is compatible with
> + * both 32-bit and 64-bit registers
> + *
> + * Acronyms:
> + * dw(data width) 0x08
> + *
> + * Map:
> + * General-Purpose Registers
> + * GPR1(sp) 0
> + * GPR2 0x8 (dw * 1)
> + * GPR13 - GPR31 0x10 ~ 0xa0 (dw * 2 ~ dw * 20)
Putting these values in a comment separate from the code that defines it
sounds like a good way to get a mismatch between the two.
> + * Foating-point registers
> + * FPR14 - FPR31 0xa8 ~ 0x130 (dw * 21 ~ dw * 38)
Call enable_kernel_fp() or similar, rather than saving FP regs here.
Likewise with altivec. And why starting at FPR14? Volatile versus
nonvolatile is irrelevant because Linux doesn't participate in the FP
ABI. Everything is non-volatile *if* we have a user FP context
resident, and everything is volatile otherwise.
> + * Timer Registers
> + * TCR 0x168 (dw * 45)
> + * TB(64bit) 0x170 (dw * 46)
> + * TBU(32bit) 0x178 (dw * 47)
> + * TBL(32bit) 0x180 (dw * 48)
Why are you saving TBU/L separate from TB? They're the same thing.
> + * Interrupt Registers
> + * IVPR 0x188 (dw * 49)
> + * IVOR0 - IVOR15 0x190 ~ 0x208 (dw * 50 ~ dw * 65)
> + * IVOR32 - IVOR41 0x210 ~ 0x258 (dw * 66 ~ dw * 75)
What about IVOR42 (LRAT error)?
> + * Software-Use Registers
> + * SPRG1 0x260 (dw * 76), 64-bit need to save.
> + * SPRG3 0x268 (dw * 77), 32-bit need to save.
What about "CPU and NUMA node for VDSO getcpu" on 64-bit? Currently
SPRG3, but it will need to change for critical interrupt support.
> + * MMU Registers
> + * PID0 - PID2 0x270 ~ 0x280 (dw * 78 ~ dw * 80)
PID1/PID2 are e500v1/v2 only -- and Linux doesn't use them outside of
KVM (and you're not in KVM when you're running this code).
Are we ever going to have a non-zero PID at this point?
> + * Debug Registers
> + * DBCR0 - DBCR2 0x288 ~ 0x298 (dw * 81 ~ dw * 83)
> + * IAC1 - IAC4 0x2a0 ~ 0x2b8 (dw * 84 ~ dw * 87)
> + * DAC1 - DAC2 0x2c0 ~ 0x2c8 (dw * 88 ~ dw * 89)
> + *
> + */
IAC3-4 are not implemented on e500.
Do we really need to save the debug registers? We're not going to be in
a debugged process when we do suspend. If the concern is kgdb, it
probably needs to be told to get out of the way during suspend for other
reasons.
> +#define SR_GPR1 0x000
> +#define SR_GPR2 0x008
> +#define SR_GPR13 0x010
> +#define SR_FPR14 0x0a8
> +#define SR_CR 0x138
> +#define SR_LR 0x140
> +#define SR_MSR 0x148
These are very vague names to be putting in a header file.
> +/*
> + * hibernation and deepsleep save/restore different number of registers,
> + * use these flags to indicate.
> + */
> +#define HIBERNATION_FLAG 1
> +#define DEEPSLEEP_FLAG 2
Again, namespacing -- but why is hibernation using this at all? What's
wrong with the existing hibernation support?
> diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
> index fcc9a89..64acae6 100644
> --- a/arch/powerpc/kernel/Makefile
> +++ b/arch/powerpc/kernel/Makefile
> @@ -73,6 +73,7 @@ obj-$(CONFIG_HIBERNATION) += swsusp_booke.o
> else
> obj-$(CONFIG_HIBERNATION) += swsusp_$(CONFIG_WORD_SIZE).o
> endif
> +obj-$(CONFIG_E500) += booke_save_regs.o
Shouldn't this depend on whether suspend is enabled?
> diff --git a/arch/powerpc/kernel/booke_save_regs.S b/arch/powerpc/kernel/booke_save_regs.S
> new file mode 100644
> index 0000000..9ccd576
> --- /dev/null
> +++ b/arch/powerpc/kernel/booke_save_regs.S
> @@ -0,0 +1,361 @@
> +/*
> + * Freescale Power Management, Save/Restore core state
> + *
> + * Copyright 2014 Freescale Semiconductor, Inc.
> + * Author: Wang Dongsheng <dongsheng.wang@freescale.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 <asm/ppc_asm.h>
> +#include <asm/booke_save_regs.h>
> +
> +/*
> + * Supported Core List:
> + * E500v1, E500v2, E500MC, E5500, E6500.
> + */
> +
> +/* Save/Restore register operation define */
> +#define do_save_gpr_reg(reg, addr) \
> + PPC_STL reg, addr(r10)
> +
> +#define do_save_fpr_reg(reg, addr) \
> + stfd reg, addr(r10)
> +
> +#define do_save_spr_reg(reg, addr) \
> + mfspr r0, SPRN_##reg ;\
> + PPC_STL r0, addr(r10)
> +
> +#define do_save_special_reg(special, addr) \
> + mf##special r0 ;\
> + PPC_STL r0, addr(r10)
> +
> +#define do_restore_gpr_reg(reg, addr) \
> + PPC_LL reg, addr(r10)
> +
> +#define do_restore_fpr_reg(reg, addr) \
> + lfd reg, addr(r10)
> +
> +#define do_restore_spr_reg(reg, addr) \
> + PPC_LL r0, addr(r10) ;\
> + mtspr SPRN_##reg, r0
> +
> +#define do_restore_special_reg(special, addr) \
> + PPC_LL r0, addr(r10) ;\
> + mt##special r0
> +
> +#define do_sr_general_gpr_regs(func) \
> + do_##func##_gpr_reg(r1, SR_GPR1) ;\
> + do_##func##_gpr_reg(r2, SR_GPR2) ;\
> + do_##func##_gpr_reg(r13, SR_GPR13 + 0x00) ;\
> + do_##func##_gpr_reg(r14, SR_GPR13 + 0x08) ;\
> + do_##func##_gpr_reg(r15, SR_GPR13 + 0x10) ;\
> + do_##func##_gpr_reg(r16, SR_GPR13 + 0x18) ;\
> + do_##func##_gpr_reg(r17, SR_GPR13 + 0x20) ;\
> + do_##func##_gpr_reg(r18, SR_GPR13 + 0x28) ;\
> + do_##func##_gpr_reg(r19, SR_GPR13 + 0x30) ;\
> + do_##func##_gpr_reg(r20, SR_GPR13 + 0x38) ;\
> + do_##func##_gpr_reg(r21, SR_GPR13 + 0x40) ;\
> + do_##func##_gpr_reg(r22, SR_GPR13 + 0x48) ;\
> + do_##func##_gpr_reg(r23, SR_GPR13 + 0x50) ;\
> + do_##func##_gpr_reg(r24, SR_GPR13 + 0x58) ;\
> + do_##func##_gpr_reg(r25, SR_GPR13 + 0x60) ;\
> + do_##func##_gpr_reg(r26, SR_GPR13 + 0x68) ;\
> + do_##func##_gpr_reg(r27, SR_GPR13 + 0x70) ;\
> + do_##func##_gpr_reg(r28, SR_GPR13 + 0x78) ;\
> + do_##func##_gpr_reg(r29, SR_GPR13 + 0x80) ;\
> + do_##func##_gpr_reg(r30, SR_GPR13 + 0x88) ;\
> + do_##func##_gpr_reg(r31, SR_GPR13 + 0x90)
> +
> +#define do_sr_general_pcr_regs(func) \
> + do_##func##_spr_reg(EPCR, SR_EPCR) ;\
> + do_##func##_spr_reg(HID0, SR_HID0 + 0x00)
> +
> +#define do_sr_e500_pcr_regs(func) \
> + do_##func##_spr_reg(HID1, SR_HID0 + 0x08)
PCR?
In the comments you said "Only e500, e500v2 need to save HID0 - HID1",
yet you save HID0 in the "general" macro.
> +#define do_sr_save_tb_regs \
> + do_save_spr_reg(TBRU, SR_TBU) ;\
> + do_save_spr_reg(TBRL, SR_TBL)
What if TBU increments between those two reads? Use the standard
sequence to read the timebase.
> +#define do_sr_interrupt_regs(func) \
> + do_##func##_spr_reg(IVPR, SR_IVPR) ;\
> + do_##func##_spr_reg(IVOR0, SR_IVOR0 + 0x00) ;\
> + do_##func##_spr_reg(IVOR1, SR_IVOR0 + 0x08) ;\
> + do_##func##_spr_reg(IVOR2, SR_IVOR0 + 0x10) ;\
> + do_##func##_spr_reg(IVOR3, SR_IVOR0 + 0x18) ;\
> + do_##func##_spr_reg(IVOR4, SR_IVOR0 + 0x20) ;\
> + do_##func##_spr_reg(IVOR5, SR_IVOR0 + 0x28) ;\
> + do_##func##_spr_reg(IVOR6, SR_IVOR0 + 0x30) ;\
> + do_##func##_spr_reg(IVOR7, SR_IVOR0 + 0x38) ;\
> + do_##func##_spr_reg(IVOR8, SR_IVOR0 + 0x40) ;\
> + do_##func##_spr_reg(IVOR10, SR_IVOR0 + 0x50) ;\
> + do_##func##_spr_reg(IVOR11, SR_IVOR0 + 0x58) ;\
> + do_##func##_spr_reg(IVOR12, SR_IVOR0 + 0x60) ;\
> + do_##func##_spr_reg(IVOR13, SR_IVOR0 + 0x68) ;\
> + do_##func##_spr_reg(IVOR14, SR_IVOR0 + 0x70) ;\
> + do_##func##_spr_reg(IVOR15, SR_IVOR0 + 0x78)
> +
> +#define do_e500_sr_interrupt_regs(func) \
> + do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
> + do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
> + do_##func##_spr_reg(IVOR34, SR_IVOR32 + 0x10)
> +
> +#define do_e500mc_sr_interrupt_regs(func) \
> + do_##func##_spr_reg(IVOR9, SR_IVOR0 + 0x48) ;\
> + do_##func##_spr_reg(IVOR35, SR_IVOR32 + 0x18) ;\
> + do_##func##_spr_reg(IVOR36, SR_IVOR32 + 0x20) ;\
> + do_##func##_spr_reg(IVOR37, SR_IVOR32 + 0x28) ;\
> + do_##func##_spr_reg(IVOR38, SR_IVOR32 + 0x30) ;\
> + do_##func##_spr_reg(IVOR39, SR_IVOR32 + 0x38) ;\
> + do_##func##_spr_reg(IVOR40, SR_IVOR32 + 0x40) ;\
> + do_##func##_spr_reg(IVOR41, SR_IVOR32 + 0x48)
> +
> +#define do_e5500_sr_interrupt_regs(func) \
> + do_e500mc_sr_interrupt_regs(func)
> +
> +#define do_e6500_sr_interrupt_regs(func) \
> + do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
> + do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
> + do_e5500_sr_interrupt_regs(func)
> +
> +#define do_sr_general_software_regs(func) \
> + do_##func##_spr_reg(SPRG1, SR_SPRG1) ;\
> + do_##func##_spr_reg(SPRG3, SR_SPRG3) ;\
> + do_##func##_spr_reg(PID0, SR_PID0)
> +
> +#define do_sr_e500_mmu_regs(func) \
> + do_##func##_spr_reg(PID1, SR_PID0 + 0x08) ;\
> + do_##func##_spr_reg(PID2, SR_PID0 + 0x10)
> +
> +#define do_sr_debug_regs(func) \
> + do_##func##_spr_reg(DBCR0, SR_DBCR0 + 0x00) ;\
> + do_##func##_spr_reg(DBCR1, SR_DBCR0 + 0x08) ;\
> + do_##func##_spr_reg(DBCR2, SR_DBCR0 + 0x10) ;\
> + do_##func##_spr_reg(IAC1, SR_IAC1 + 0x00) ;\
> + do_##func##_spr_reg(IAC2, SR_IAC1 + 0x08) ;\
> + do_##func##_spr_reg(DAC1, SR_DAC1 + 0x00) ;\
> + do_##func##_spr_reg(DAC2, SR_DAC1 + 0x08)
> +
> +#define do_e6500_sr_debug_regs(func) \
> + do_##func##_spr_reg(IAC3, SR_IAC1 + 0x10) ;\
> + do_##func##_spr_reg(IAC4, SR_IAC1 + 0x18)
> +
> + .section .text
> + .align 5
> +booke_cpu_base_save:
> + do_sr_general_gpr_regs(save)
> + do_sr_general_pcr_regs(save)
> + do_sr_general_software_regs(save)
> +1:
> + mfspr r5, SPRN_TBRU
> + do_sr_general_time_regs(save)
> + mfspr r6, SPRN_TBRU
> + cmpw r5, r6
> + bne 1b
Oh, here's where you deal with that. Why? It just obfuscates things.
> +booke_cpu_base_restore:
> + do_sr_general_gpr_regs(restore)
> + do_sr_general_pcr_regs(restore)
> + do_sr_general_software_regs(restore)
> +
> + isync
> +
> + /* Restore Time registers, clear tb lower to avoid wrap */
> + li r0, 0
> + mtspr SPRN_TBWL, r0
> + do_sr_general_time_regs(restore)
Why is zeroing TBL not done in the same place as you load the new TB?
> +/* Base registers, e500v1, e500v2 need to do some special save/restore */
> +e500_base_special_save:
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500V1@l
> + cmpw r11, r12
> + beq 1f
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500V2@l
> + cmpw r11, r12
> + bne 2f
> +1:
> + do_sr_e500_pcr_regs(save)
> + do_sr_e500_mmu_regs(save)
> +2:
> + blr
> +
> +e500_base_special_restore:
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500V1@l
> + cmpw r11, r12
> + beq 1f
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500V2@l
> + cmpw r11, r12
> + bne 2f
> +1:
> + do_sr_e500_pcr_regs(save)
> + do_sr_e500_mmu_regs(save)
> +2:
> + blr
Why is this separate from the other CPU-specific "append" code?
> +booke_cpu_append_save:
> + mfspr r0, SPRN_PVR
> + rlwinm r11, r0, 16, 16, 31
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E6500@l
> + cmpw r11, r12
> + beq e6500_append_save
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E5500@l
> + cmpw r11, r12
> + beq e5500_append_save
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500MC@l
> + cmpw r11, r12
> + beq e500mc_append_save
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500V2@l
> + cmpw r11, r12
> + beq e500v2_append_save
> +
> + lis r12, 0
> + ori r12, r12, PVR_VER_E500V1@l
> + cmpw r11, r12
> + beq e500v1_append_save
> + b 1f
> +
> +e6500_append_save:
> + do_e6500_sr_interrupt_regs(save)
> + do_e6500_sr_debug_regs(save)
> + b 1f
> +
> +e5500_append_save:
> + do_e5500_sr_interrupt_regs(save)
> + b 1f
> +
> +e500mc_append_save:
> + do_e500mc_sr_interrupt_regs(save)
> + b 1f
> +
> +e500v2_append_save:
> +e500v1_append_save:
> + do_e500_sr_interrupt_regs(save)
> +1:
> + do_sr_interrupt_regs(save)
> + do_sr_debug_regs(save)
> +
> + blr
What is meant by "append" here?
> +/*
> + * r3 = the address of buffer
> + * r4 = type: HIBERNATION_FLAG or DEEPSLEEP_FLAG
> + */
> +_GLOBAL(booke_cpu_state_save)
> + mflr r9
> + mr r10, r3
> +
> + cmpwi r4, HIBERNATION_FLAG
> + beq 1f
> + bl booke_cpu_append_save
> +1:
> + bl e500_base_special_save
> + bl booke_cpu_base_save
> +
> + mtlr r9
> + blr
You're assuming a special ABI from these subfunctions (e.g. r9
non-volatile) but I don't see any comment to that effect on those
functions.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers
2014-03-12 0:45 ` Scott Wood
@ 2014-03-12 9:42 ` Chenhui Zhao
2014-03-14 23:01 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 9:42 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin, Wang Dongsheng-B40534
On Tue, Mar 11, 2014 at 07:45:14PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > From: Wang Dongsheng <dongsheng.wang@freescale.com>
> >
> > Add booke_cpu_state_save() and booke_cpu_state_restore() functions which can be
> > used to save/restore CPU's registers in the case of deep sleep and hibernation.
> >
> > Supported processors: E6500, E5500, E500MC, E500v2 and E500v1.
> >
> > Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > ---
> > arch/powerpc/include/asm/booke_save_regs.h | 96 ++++++++
> > arch/powerpc/kernel/Makefile | 1 +
> > arch/powerpc/kernel/booke_save_regs.S | 361 ++++++++++++++++++++++++++++
> > 3 files changed, 458 insertions(+), 0 deletions(-)
> > create mode 100644 arch/powerpc/include/asm/booke_save_regs.h
> > create mode 100644 arch/powerpc/kernel/booke_save_regs.S
> >
> > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > new file mode 100644
> > index 0000000..87c357a
> > --- /dev/null
> > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > @@ -0,0 +1,96 @@
> > +/*
> > + * Save/restore e500 series core registers
>
> Filename says booke, comment says e500.
>
> Filename and comment also fail to point out that this is specifically
> for standby/suspend, not for hibernate which is implemented in
> swsusp_booke.S/swsusp_asm64.S.
Sorry for inconsistency. Will changes e500 to booke.
Hibernation and suspend can share the code.
>
> > + *
> > + * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
> > + *
> > + * Copyright 2014 Freescale Semiconductor Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#ifndef __ASM_FSL_SLEEP_H
> > +#define __ASM_FSL_SLEEP_H
> > +
> > +/*
> > + * 8 bytes for each register, which is compatible with
> > + * both 32-bit and 64-bit registers
> > + *
> > + * Acronyms:
> > + * dw(data width) 0x08
> > + *
> > + * Map:
> > + * General-Purpose Registers
> > + * GPR1(sp) 0
> > + * GPR2 0x8 (dw * 1)
> > + * GPR13 - GPR31 0x10 ~ 0xa0 (dw * 2 ~ dw * 20)
>
> Putting these values in a comment separate from the code that defines it
> sounds like a good way to get a mismatch between the two.
Ok.
>
> > + * Foating-point registers
> > + * FPR14 - FPR31 0xa8 ~ 0x130 (dw * 21 ~ dw * 38)
>
> Call enable_kernel_fp() or similar, rather than saving FP regs here.
> Likewise with altivec. And why starting at FPR14? Volatile versus
> nonvolatile is irrelevant because Linux doesn't participate in the FP
> ABI. Everything is non-volatile *if* we have a user FP context
> resident, and everything is volatile otherwise.
Will remove them.
>
> > + * Timer Registers
> > + * TCR 0x168 (dw * 45)
> > + * TB(64bit) 0x170 (dw * 46)
> > + * TBU(32bit) 0x178 (dw * 47)
> > + * TBL(32bit) 0x180 (dw * 48)
>
> Why are you saving TBU/L separate from TB? They're the same thing.
Will remove TBU and TBL.
>
> > + * Interrupt Registers
> > + * IVPR 0x188 (dw * 49)
> > + * IVOR0 - IVOR15 0x190 ~ 0x208 (dw * 50 ~ dw * 65)
> > + * IVOR32 - IVOR41 0x210 ~ 0x258 (dw * 66 ~ dw * 75)
>
> What about IVOR42 (LRAT error)?
Will add it.
>
> > + * Software-Use Registers
> > + * SPRG1 0x260 (dw * 76), 64-bit need to save.
> > + * SPRG3 0x268 (dw * 77), 32-bit need to save.
>
> What about "CPU and NUMA node for VDSO getcpu" on 64-bit? Currently
> SPRG3, but it will need to change for critical interrupt support.
>
> > + * MMU Registers
> > + * PID0 - PID2 0x270 ~ 0x280 (dw * 78 ~ dw * 80)
>
> PID1/PID2 are e500v1/v2 only -- and Linux doesn't use them outside of
> KVM (and you're not in KVM when you're running this code).
>
> Are we ever going to have a non-zero PID at this point?
I incline to the view that saving all registers regardless of used or
unused. The good point is that it can be compliant to the future
changes of the usage of registers.
What do you think?
>
> > + * Debug Registers
> > + * DBCR0 - DBCR2 0x288 ~ 0x298 (dw * 81 ~ dw * 83)
> > + * IAC1 - IAC4 0x2a0 ~ 0x2b8 (dw * 84 ~ dw * 87)
> > + * DAC1 - DAC2 0x2c0 ~ 0x2c8 (dw * 88 ~ dw * 89)
> > + *
> > + */
>
> IAC3-4 are not implemented on e500.
>
> Do we really need to save the debug registers? We're not going to be in
> a debugged process when we do suspend. If the concern is kgdb, it
> probably needs to be told to get out of the way during suspend for other
> reasons.
I think in the ideal case the suspend would not break any context. We
should try to save/restore all cpu state. Of cause, trade-off is
unavoidable in practice.
>
> > +#define SR_GPR1 0x000
> > +#define SR_GPR2 0x008
> > +#define SR_GPR13 0x010
> > +#define SR_FPR14 0x0a8
> > +#define SR_CR 0x138
> > +#define SR_LR 0x140
> > +#define SR_MSR 0x148
>
> These are very vague names to be putting in a header file.
How about BOOKE_xx_OFFSET?
>
> > +/*
> > + * hibernation and deepsleep save/restore different number of registers,
> > + * use these flags to indicate.
> > + */
> > +#define HIBERNATION_FLAG 1
> > +#define DEEPSLEEP_FLAG 2
>
> Again, namespacing -- but why is hibernation using this at all? What's
> wrong with the existing hibernation support?
How about BOOKE_HIBERNATION_FLAG?
Just wish to share code between hibernation and suspend.
>
> > diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
> > index fcc9a89..64acae6 100644
> > --- a/arch/powerpc/kernel/Makefile
> > +++ b/arch/powerpc/kernel/Makefile
> > @@ -73,6 +73,7 @@ obj-$(CONFIG_HIBERNATION) += swsusp_booke.o
> > else
> > obj-$(CONFIG_HIBERNATION) += swsusp_$(CONFIG_WORD_SIZE).o
> > endif
> > +obj-$(CONFIG_E500) += booke_save_regs.o
>
> Shouldn't this depend on whether suspend is enabled?
>
> > diff --git a/arch/powerpc/kernel/booke_save_regs.S b/arch/powerpc/kernel/booke_save_regs.S
> > new file mode 100644
> > index 0000000..9ccd576
> > --- /dev/null
> > +++ b/arch/powerpc/kernel/booke_save_regs.S
> > @@ -0,0 +1,361 @@
> > +/*
> > + * Freescale Power Management, Save/Restore core state
> > + *
> > + * Copyright 2014 Freescale Semiconductor, Inc.
> > + * Author: Wang Dongsheng <dongsheng.wang@freescale.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 <asm/ppc_asm.h>
> > +#include <asm/booke_save_regs.h>
> > +
> > +/*
> > + * Supported Core List:
> > + * E500v1, E500v2, E500MC, E5500, E6500.
> > + */
> > +
> > +/* Save/Restore register operation define */
> > +#define do_save_gpr_reg(reg, addr) \
> > + PPC_STL reg, addr(r10)
> > +
> > +#define do_save_fpr_reg(reg, addr) \
> > + stfd reg, addr(r10)
> > +
> > +#define do_save_spr_reg(reg, addr) \
> > + mfspr r0, SPRN_##reg ;\
> > + PPC_STL r0, addr(r10)
> > +
> > +#define do_save_special_reg(special, addr) \
> > + mf##special r0 ;\
> > + PPC_STL r0, addr(r10)
> > +
> > +#define do_restore_gpr_reg(reg, addr) \
> > + PPC_LL reg, addr(r10)
> > +
> > +#define do_restore_fpr_reg(reg, addr) \
> > + lfd reg, addr(r10)
> > +
> > +#define do_restore_spr_reg(reg, addr) \
> > + PPC_LL r0, addr(r10) ;\
> > + mtspr SPRN_##reg, r0
> > +
> > +#define do_restore_special_reg(special, addr) \
> > + PPC_LL r0, addr(r10) ;\
> > + mt##special r0
> > +
> > +#define do_sr_general_gpr_regs(func) \
> > + do_##func##_gpr_reg(r1, SR_GPR1) ;\
> > + do_##func##_gpr_reg(r2, SR_GPR2) ;\
> > + do_##func##_gpr_reg(r13, SR_GPR13 + 0x00) ;\
> > + do_##func##_gpr_reg(r14, SR_GPR13 + 0x08) ;\
> > + do_##func##_gpr_reg(r15, SR_GPR13 + 0x10) ;\
> > + do_##func##_gpr_reg(r16, SR_GPR13 + 0x18) ;\
> > + do_##func##_gpr_reg(r17, SR_GPR13 + 0x20) ;\
> > + do_##func##_gpr_reg(r18, SR_GPR13 + 0x28) ;\
> > + do_##func##_gpr_reg(r19, SR_GPR13 + 0x30) ;\
> > + do_##func##_gpr_reg(r20, SR_GPR13 + 0x38) ;\
> > + do_##func##_gpr_reg(r21, SR_GPR13 + 0x40) ;\
> > + do_##func##_gpr_reg(r22, SR_GPR13 + 0x48) ;\
> > + do_##func##_gpr_reg(r23, SR_GPR13 + 0x50) ;\
> > + do_##func##_gpr_reg(r24, SR_GPR13 + 0x58) ;\
> > + do_##func##_gpr_reg(r25, SR_GPR13 + 0x60) ;\
> > + do_##func##_gpr_reg(r26, SR_GPR13 + 0x68) ;\
> > + do_##func##_gpr_reg(r27, SR_GPR13 + 0x70) ;\
> > + do_##func##_gpr_reg(r28, SR_GPR13 + 0x78) ;\
> > + do_##func##_gpr_reg(r29, SR_GPR13 + 0x80) ;\
> > + do_##func##_gpr_reg(r30, SR_GPR13 + 0x88) ;\
> > + do_##func##_gpr_reg(r31, SR_GPR13 + 0x90)
> > +
> > +#define do_sr_general_pcr_regs(func) \
> > + do_##func##_spr_reg(EPCR, SR_EPCR) ;\
> > + do_##func##_spr_reg(HID0, SR_HID0 + 0x00)
> > +
> > +#define do_sr_e500_pcr_regs(func) \
> > + do_##func##_spr_reg(HID1, SR_HID0 + 0x08)
>
> PCR?
>
> In the comments you said "Only e500, e500v2 need to save HID0 - HID1",
> yet you save HID0 in the "general" macro.
Will change it.
>
> > +#define do_sr_save_tb_regs \
> > + do_save_spr_reg(TBRU, SR_TBU) ;\
> > + do_save_spr_reg(TBRL, SR_TBL)
>
> What if TBU increments between those two reads? Use the standard
> sequence to read the timebase.
>
> > +#define do_sr_interrupt_regs(func) \
> > + do_##func##_spr_reg(IVPR, SR_IVPR) ;\
> > + do_##func##_spr_reg(IVOR0, SR_IVOR0 + 0x00) ;\
> > + do_##func##_spr_reg(IVOR1, SR_IVOR0 + 0x08) ;\
> > + do_##func##_spr_reg(IVOR2, SR_IVOR0 + 0x10) ;\
> > + do_##func##_spr_reg(IVOR3, SR_IVOR0 + 0x18) ;\
> > + do_##func##_spr_reg(IVOR4, SR_IVOR0 + 0x20) ;\
> > + do_##func##_spr_reg(IVOR5, SR_IVOR0 + 0x28) ;\
> > + do_##func##_spr_reg(IVOR6, SR_IVOR0 + 0x30) ;\
> > + do_##func##_spr_reg(IVOR7, SR_IVOR0 + 0x38) ;\
> > + do_##func##_spr_reg(IVOR8, SR_IVOR0 + 0x40) ;\
> > + do_##func##_spr_reg(IVOR10, SR_IVOR0 + 0x50) ;\
> > + do_##func##_spr_reg(IVOR11, SR_IVOR0 + 0x58) ;\
> > + do_##func##_spr_reg(IVOR12, SR_IVOR0 + 0x60) ;\
> > + do_##func##_spr_reg(IVOR13, SR_IVOR0 + 0x68) ;\
> > + do_##func##_spr_reg(IVOR14, SR_IVOR0 + 0x70) ;\
> > + do_##func##_spr_reg(IVOR15, SR_IVOR0 + 0x78)
> > +
> > +#define do_e500_sr_interrupt_regs(func) \
> > + do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
> > + do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
> > + do_##func##_spr_reg(IVOR34, SR_IVOR32 + 0x10)
> > +
> > +#define do_e500mc_sr_interrupt_regs(func) \
> > + do_##func##_spr_reg(IVOR9, SR_IVOR0 + 0x48) ;\
> > + do_##func##_spr_reg(IVOR35, SR_IVOR32 + 0x18) ;\
> > + do_##func##_spr_reg(IVOR36, SR_IVOR32 + 0x20) ;\
> > + do_##func##_spr_reg(IVOR37, SR_IVOR32 + 0x28) ;\
> > + do_##func##_spr_reg(IVOR38, SR_IVOR32 + 0x30) ;\
> > + do_##func##_spr_reg(IVOR39, SR_IVOR32 + 0x38) ;\
> > + do_##func##_spr_reg(IVOR40, SR_IVOR32 + 0x40) ;\
> > + do_##func##_spr_reg(IVOR41, SR_IVOR32 + 0x48)
> > +
> > +#define do_e5500_sr_interrupt_regs(func) \
> > + do_e500mc_sr_interrupt_regs(func)
> > +
> > +#define do_e6500_sr_interrupt_regs(func) \
> > + do_##func##_spr_reg(IVOR32, SR_IVOR32 + 0x00) ;\
> > + do_##func##_spr_reg(IVOR33, SR_IVOR32 + 0x08) ;\
> > + do_e5500_sr_interrupt_regs(func)
> > +
> > +#define do_sr_general_software_regs(func) \
> > + do_##func##_spr_reg(SPRG1, SR_SPRG1) ;\
> > + do_##func##_spr_reg(SPRG3, SR_SPRG3) ;\
> > + do_##func##_spr_reg(PID0, SR_PID0)
> > +
> > +#define do_sr_e500_mmu_regs(func) \
> > + do_##func##_spr_reg(PID1, SR_PID0 + 0x08) ;\
> > + do_##func##_spr_reg(PID2, SR_PID0 + 0x10)
> > +
> > +#define do_sr_debug_regs(func) \
> > + do_##func##_spr_reg(DBCR0, SR_DBCR0 + 0x00) ;\
> > + do_##func##_spr_reg(DBCR1, SR_DBCR0 + 0x08) ;\
> > + do_##func##_spr_reg(DBCR2, SR_DBCR0 + 0x10) ;\
> > + do_##func##_spr_reg(IAC1, SR_IAC1 + 0x00) ;\
> > + do_##func##_spr_reg(IAC2, SR_IAC1 + 0x08) ;\
> > + do_##func##_spr_reg(DAC1, SR_DAC1 + 0x00) ;\
> > + do_##func##_spr_reg(DAC2, SR_DAC1 + 0x08)
> > +
> > +#define do_e6500_sr_debug_regs(func) \
> > + do_##func##_spr_reg(IAC3, SR_IAC1 + 0x10) ;\
> > + do_##func##_spr_reg(IAC4, SR_IAC1 + 0x18)
> > +
> > + .section .text
> > + .align 5
> > +booke_cpu_base_save:
> > + do_sr_general_gpr_regs(save)
> > + do_sr_general_pcr_regs(save)
> > + do_sr_general_software_regs(save)
> > +1:
> > + mfspr r5, SPRN_TBRU
> > + do_sr_general_time_regs(save)
> > + mfspr r6, SPRN_TBRU
> > + cmpw r5, r6
> > + bne 1b
>
> Oh, here's where you deal with that. Why? It just obfuscates things.
Will make it more readable.
>
> > +booke_cpu_base_restore:
> > + do_sr_general_gpr_regs(restore)
> > + do_sr_general_pcr_regs(restore)
> > + do_sr_general_software_regs(restore)
> > +
> > + isync
> > +
> > + /* Restore Time registers, clear tb lower to avoid wrap */
> > + li r0, 0
> > + mtspr SPRN_TBWL, r0
> > + do_sr_general_time_regs(restore)
>
> Why is zeroing TBL not done in the same place as you load the new TB?
Will fix it.
>
> > +/* Base registers, e500v1, e500v2 need to do some special save/restore */
> > +e500_base_special_save:
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500V1@l
> > + cmpw r11, r12
> > + beq 1f
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500V2@l
> > + cmpw r11, r12
> > + bne 2f
> > +1:
> > + do_sr_e500_pcr_regs(save)
> > + do_sr_e500_mmu_regs(save)
> > +2:
> > + blr
> > +
> > +e500_base_special_restore:
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500V1@l
> > + cmpw r11, r12
> > + beq 1f
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500V2@l
> > + cmpw r11, r12
> > + bne 2f
> > +1:
> > + do_sr_e500_pcr_regs(save)
> > + do_sr_e500_mmu_regs(save)
> > +2:
> > + blr
>
> Why is this separate from the other CPU-specific "append" code?
>
> > +booke_cpu_append_save:
> > + mfspr r0, SPRN_PVR
> > + rlwinm r11, r0, 16, 16, 31
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E6500@l
> > + cmpw r11, r12
> > + beq e6500_append_save
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E5500@l
> > + cmpw r11, r12
> > + beq e5500_append_save
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500MC@l
> > + cmpw r11, r12
> > + beq e500mc_append_save
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500V2@l
> > + cmpw r11, r12
> > + beq e500v2_append_save
> > +
> > + lis r12, 0
> > + ori r12, r12, PVR_VER_E500V1@l
> > + cmpw r11, r12
> > + beq e500v1_append_save
> > + b 1f
> > +
> > +e6500_append_save:
> > + do_e6500_sr_interrupt_regs(save)
> > + do_e6500_sr_debug_regs(save)
> > + b 1f
> > +
> > +e5500_append_save:
> > + do_e5500_sr_interrupt_regs(save)
> > + b 1f
> > +
> > +e500mc_append_save:
> > + do_e500mc_sr_interrupt_regs(save)
> > + b 1f
> > +
> > +e500v2_append_save:
> > +e500v1_append_save:
> > + do_e500_sr_interrupt_regs(save)
> > +1:
> > + do_sr_interrupt_regs(save)
> > + do_sr_debug_regs(save)
> > +
> > + blr
>
> What is meant by "append" here?
Means extra registers for specific e500 derivative core.
>
> > +/*
> > + * r3 = the address of buffer
> > + * r4 = type: HIBERNATION_FLAG or DEEPSLEEP_FLAG
> > + */
> > +_GLOBAL(booke_cpu_state_save)
> > + mflr r9
> > + mr r10, r3
> > +
> > + cmpwi r4, HIBERNATION_FLAG
> > + beq 1f
> > + bl booke_cpu_append_save
> > +1:
> > + bl e500_base_special_save
> > + bl booke_cpu_base_save
> > +
> > + mtlr r9
> > + blr
>
> You're assuming a special ABI from these subfunctions (e.g. r9
> non-volatile) but I don't see any comment to that effect on those
> functions.
>
> -Scott
Will add comments.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers
2014-03-12 9:42 ` Chenhui Zhao
@ 2014-03-14 23:01 ` Scott Wood
2014-03-17 10:50 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-14 23:01 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin, Wang Dongsheng-B40534
On Wed, 2014-03-12 at 17:42 +0800, Chenhui Zhao wrote:
> On Tue, Mar 11, 2014 at 07:45:14PM -0500, Scott Wood wrote:
> > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > From: Wang Dongsheng <dongsheng.wang@freescale.com>
> > >
> > > Add booke_cpu_state_save() and booke_cpu_state_restore() functions which can be
> > > used to save/restore CPU's registers in the case of deep sleep and hibernation.
> > >
> > > Supported processors: E6500, E5500, E500MC, E500v2 and E500v1.
> > >
> > > Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> > > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > > ---
> > > arch/powerpc/include/asm/booke_save_regs.h | 96 ++++++++
> > > arch/powerpc/kernel/Makefile | 1 +
> > > arch/powerpc/kernel/booke_save_regs.S | 361 ++++++++++++++++++++++++++++
> > > 3 files changed, 458 insertions(+), 0 deletions(-)
> > > create mode 100644 arch/powerpc/include/asm/booke_save_regs.h
> > > create mode 100644 arch/powerpc/kernel/booke_save_regs.S
> > >
> > > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > > new file mode 100644
> > > index 0000000..87c357a
> > > --- /dev/null
> > > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > > @@ -0,0 +1,96 @@
> > > +/*
> > > + * Save/restore e500 series core registers
> >
> > Filename says booke, comment says e500.
> >
> > Filename and comment also fail to point out that this is specifically
> > for standby/suspend, not for hibernate which is implemented in
> > swsusp_booke.S/swsusp_asm64.S.
>
> Sorry for inconsistency. Will changes e500 to booke.
> Hibernation and suspend can share the code.
Maybe they could, but AFAICT this patchset doesn't make that happen --
and I'm not convinced that the churn would be worthwhile. Note that
swsusp_asm64.S is not just for booke, so most of that file would not be
going away if you did make such a change.
I also don't like the way it looks like booke_save_regs.S is a booke
version of ppc_save_regs.S, even though they serve different purposes
and ppc_save_regs.S is still relevant to booke.
> > > + * Software-Use Registers
> > > + * SPRG1 0x260 (dw * 76), 64-bit need to save.
> > > + * SPRG3 0x268 (dw * 77), 32-bit need to save.
> >
> > What about "CPU and NUMA node for VDSO getcpu" on 64-bit? Currently
> > SPRG3, but it will need to change for critical interrupt support.
> >
> > > + * MMU Registers
> > > + * PID0 - PID2 0x270 ~ 0x280 (dw * 78 ~ dw * 80)
> >
> > PID1/PID2 are e500v1/v2 only -- and Linux doesn't use them outside of
> > KVM (and you're not in KVM when you're running this code).
> >
> > Are we ever going to have a non-zero PID at this point?
>
> I incline to the view that saving all registers regardless of used or
> unused. The good point is that it can be compliant to the future
> changes of the usage of registers.
>
> What do you think?
I agree to a certain extent, but balance it with the complexity of
dealing with registers that don't exist on all booke chips. If they
don't really need to be saved, why go through the hassle of conditional
code?
> > > + * Debug Registers
> > > + * DBCR0 - DBCR2 0x288 ~ 0x298 (dw * 81 ~ dw * 83)
> > > + * IAC1 - IAC4 0x2a0 ~ 0x2b8 (dw * 84 ~ dw * 87)
> > > + * DAC1 - DAC2 0x2c0 ~ 0x2c8 (dw * 88 ~ dw * 89)
> > > + *
> > > + */
> >
> > IAC3-4 are not implemented on e500.
> >
> > Do we really need to save the debug registers? We're not going to be in
> > a debugged process when we do suspend. If the concern is kgdb, it
> > probably needs to be told to get out of the way during suspend for other
> > reasons.
>
> I think in the ideal case the suspend would not break any context. We
> should try to save/restore all cpu state. Of cause, trade-off is
> unavoidable in practice.
>
> >
> > > +#define SR_GPR1 0x000
> > > +#define SR_GPR2 0x008
> > > +#define SR_GPR13 0x010
> > > +#define SR_FPR14 0x0a8
> > > +#define SR_CR 0x138
> > > +#define SR_LR 0x140
> > > +#define SR_MSR 0x148
> >
> > These are very vague names to be putting in a header file.
>
> How about BOOKE_xx_OFFSET?
Better, but does it need to be in a public header file at all?
> > > +/*
> > > + * hibernation and deepsleep save/restore different number of registers,
> > > + * use these flags to indicate.
> > > + */
> > > +#define HIBERNATION_FLAG 1
> > > +#define DEEPSLEEP_FLAG 2
> >
> > Again, namespacing -- but why is hibernation using this at all? What's
> > wrong with the existing hibernation support?
>
> How about BOOKE_HIBERNATION_FLAG?
>
> Just wish to share code between hibernation and suspend.
No need until and unless you actually implement the change for
hibernation to use this. As is, this is dead and untestable code.
> > > +booke_cpu_append_save:
> > > + mfspr r0, SPRN_PVR
> > > + rlwinm r11, r0, 16, 16, 31
> > > +
> > > + lis r12, 0
> > > + ori r12, r12, PVR_VER_E6500@l
> > > + cmpw r11, r12
> > > + beq e6500_append_save
> > > +
> > > + lis r12, 0
> > > + ori r12, r12, PVR_VER_E5500@l
> > > + cmpw r11, r12
> > > + beq e5500_append_save
> > > +
> > > + lis r12, 0
> > > + ori r12, r12, PVR_VER_E500MC@l
> > > + cmpw r11, r12
> > > + beq e500mc_append_save
> > > +
> > > + lis r12, 0
> > > + ori r12, r12, PVR_VER_E500V2@l
> > > + cmpw r11, r12
> > > + beq e500v2_append_save
> > > +
> > > + lis r12, 0
> > > + ori r12, r12, PVR_VER_E500V1@l
> > > + cmpw r11, r12
> > > + beq e500v1_append_save
> > > + b 1f
> > > +
> > > +e6500_append_save:
> > > + do_e6500_sr_interrupt_regs(save)
> > > + do_e6500_sr_debug_regs(save)
> > > + b 1f
> > > +
> > > +e5500_append_save:
> > > + do_e5500_sr_interrupt_regs(save)
> > > + b 1f
> > > +
> > > +e500mc_append_save:
> > > + do_e500mc_sr_interrupt_regs(save)
> > > + b 1f
> > > +
> > > +e500v2_append_save:
> > > +e500v1_append_save:
> > > + do_e500_sr_interrupt_regs(save)
> > > +1:
> > > + do_sr_interrupt_regs(save)
> > > + do_sr_debug_regs(save)
> > > +
> > > + blr
> >
> > What is meant by "append" here?
>
> Means extra registers for specific e500 derivative core.
How is that related to skipping it in the hibernation case?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers
2014-03-14 23:01 ` Scott Wood
@ 2014-03-17 10:50 ` Chenhui Zhao
0 siblings, 0 replies; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-17 10:50 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin, Wang Dongsheng-B40534
On Fri, Mar 14, 2014 at 06:01:45PM -0500, Scott Wood wrote:
> On Wed, 2014-03-12 at 17:42 +0800, Chenhui Zhao wrote:
> > On Tue, Mar 11, 2014 at 07:45:14PM -0500, Scott Wood wrote:
> > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > From: Wang Dongsheng <dongsheng.wang@freescale.com>
> > > >
> > > > Add booke_cpu_state_save() and booke_cpu_state_restore() functions which can be
> > > > used to save/restore CPU's registers in the case of deep sleep and hibernation.
> > > >
> > > > Supported processors: E6500, E5500, E500MC, E500v2 and E500v1.
> > > >
> > > > Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> > > > Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
> > > > ---
> > > > arch/powerpc/include/asm/booke_save_regs.h | 96 ++++++++
> > > > arch/powerpc/kernel/Makefile | 1 +
> > > > arch/powerpc/kernel/booke_save_regs.S | 361 ++++++++++++++++++++++++++++
> > > > 3 files changed, 458 insertions(+), 0 deletions(-)
> > > > create mode 100644 arch/powerpc/include/asm/booke_save_regs.h
> > > > create mode 100644 arch/powerpc/kernel/booke_save_regs.S
> > > >
> > > > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > > > new file mode 100644
> > > > index 0000000..87c357a
> > > > --- /dev/null
> > > > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > > > @@ -0,0 +1,96 @@
> > > > +/*
> > > > + * Save/restore e500 series core registers
> > >
> > > Filename says booke, comment says e500.
> > >
> > > Filename and comment also fail to point out that this is specifically
> > > for standby/suspend, not for hibernate which is implemented in
> > > swsusp_booke.S/swsusp_asm64.S.
> >
> > Sorry for inconsistency. Will changes e500 to booke.
> > Hibernation and suspend can share the code.
>
> Maybe they could, but AFAICT this patchset doesn't make that happen --
> and I'm not convinced that the churn would be worthwhile. Note that
> swsusp_asm64.S is not just for booke, so most of that file would not be
> going away if you did make such a change.
OK. Let's put Hibernation aside, and change the code just for suspend.
>
> I also don't like the way it looks like booke_save_regs.S is a booke
> version of ppc_save_regs.S, even though they serve different purposes
> and ppc_save_regs.S is still relevant to booke.
>
> > > > + * Software-Use Registers
> > > > + * SPRG1 0x260 (dw * 76), 64-bit need to save.
> > > > + * SPRG3 0x268 (dw * 77), 32-bit need to save.
> > >
> > > What about "CPU and NUMA node for VDSO getcpu" on 64-bit? Currently
> > > SPRG3, but it will need to change for critical interrupt support.
> > >
> > > > + * MMU Registers
> > > > + * PID0 - PID2 0x270 ~ 0x280 (dw * 78 ~ dw * 80)
> > >
> > > PID1/PID2 are e500v1/v2 only -- and Linux doesn't use them outside of
> > > KVM (and you're not in KVM when you're running this code).
> > >
> > > Are we ever going to have a non-zero PID at this point?
> >
> > I incline to the view that saving all registers regardless of used or
> > unused. The good point is that it can be compliant to the future
> > changes of the usage of registers.
> >
> > What do you think?
>
> I agree to a certain extent, but balance it with the complexity of
> dealing with registers that don't exist on all booke chips. If they
> don't really need to be saved, why go through the hassle of conditional
> code?
I agree. For these registers, I'll check if they are really needed.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-07 4:57 [PATCH 1/9] powerpc/fsl: add PVR definition for E500MC and E5500 Chenhui Zhao
` (6 preceding siblings ...)
2014-03-07 4:58 ` [PATCH 8/9] powerpc/85xx: add save/restore functions for core registers Chenhui Zhao
@ 2014-03-07 4:58 ` Chenhui Zhao
2014-03-12 1:10 ` Scott Wood
7 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-07 4:58 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-kernel, Jason.Jin
From: Zhao Chenhui <chenhui.zhao@freescale.com>
T1040 supports 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 will be prefetched.
Due to the different initialization code between 32-bit and 64-bit, they
have seperate resume entry and precedure.
The feature supports 32-bit and 64-bit kernel mode.
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
arch/powerpc/include/asm/booke_save_regs.h | 3 +
arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
arch/powerpc/kernel/head_fsl_booke.S | 30 +++
arch/powerpc/platforms/85xx/Makefile | 2 +-
arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
arch/powerpc/sysdev/fsl_soc.h | 7 +
8 files changed, 592 insertions(+), 1 deletions(-)
create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
create mode 100644 arch/powerpc/platforms/85xx/sleep.S
diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
index 87c357a..37c1f6c 100644
--- a/arch/powerpc/include/asm/booke_save_regs.h
+++ b/arch/powerpc/include/asm/booke_save_regs.h
@@ -88,6 +88,9 @@
#define HIBERNATION_FLAG 1
#define DEEPSLEEP_FLAG 2
+#define CPLD_FLAG 1
+#define FPGA_FLAG 2
+
#ifndef __ASSEMBLY__
extern void booke_cpu_state_save(void *buf, int type);
extern void *booke_cpu_state_restore(void *buf, int type);
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index e59d6de..ea9bc28 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -318,6 +318,23 @@ flush_backside_L2_cache:
2:
blr
+#define CPC_CPCCSR0 0x0
+#define CPC_CPCCSR0_CPCFL 0x800
+
+/* r3 : the base address of CPC */
+_GLOBAL(fsl_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
+
_GLOBAL(__flush_caches_e500v2)
mflr r0
bl flush_dcache_L1
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 20204fe..3285752 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -162,6 +162,19 @@ _ENTRY(__early_start)
#include "fsl_booke_entry_mapping.S"
#undef ENTRY_MAPPING_BOOT_SETUP
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
+ /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
+ LOAD_REG_ADDR(r4, deep_sleep_flag)
+ lwz r3, 0(r4)
+ cmpwi r3, 0
+ beq 11f
+ /* clear deep_sleep_flag */
+ li r3, 0
+ stw r3, 0(r4)
+ b fsl_deepsleep_resume
+11:
+#endif
+
set_ivor:
/* Establish the interrupt vector offsets */
SET_IVOR(0, CriticalInput);
@@ -343,6 +356,23 @@ set_ivor:
lwz r11, 0(r12); /* Get Linux PTE */
#endif
+#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
+_ENTRY(__entry_deep_sleep)
+/*
+ * Bootloader will jump to here when resuming from deep sleep.
+ * After executing the init code in fsl_booke_entry_mapping.S,
+ * will jump to the real resume entry.
+ */
+ li r8, 1
+ bl 12f
+12: mflr r9
+ addi r9, r9, (deep_sleep_flag - 12b)
+ stw r8, 0(r9)
+ b __early_start
+deep_sleep_flag:
+ .long 0
+#endif
+
/*
* Interrupt vector entry code
*
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 7fae817..9a4ea86 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,7 @@
#
obj-$(CONFIG_SMP) += smp.o
ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
-obj-$(CONFIG_SUSPEND) += qoriq_pm.o
+obj-$(CONFIG_SUSPEND) += qoriq_pm.o deepsleep.o sleep.o
endif
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..ddd7185
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/deepsleep.c
@@ -0,0 +1,201 @@
+/*
+ * Support deep sleep feature
+ *
+ * Copyright 2014 Freescale Semiconductor Inc.
+ *
+ * Author: Chenhui Zhao <chenhui.zhao@freescale.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/of_platform.h>
+#include <linux/of_address.h>
+#include <asm/machdep.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/booke_save_regs.h>
+
+#define SIZE_1MB 0x100000
+#define SIZE_2MB 0x200000
+
+#define CCSR_SCFG_DPSLPCR 0xfc000
+#define CCSR_SCFG_DPSLPCR_WDRR_EN 0x1
+#define CCSR_SCFG_SPARECR2 0xfc504
+#define CCSR_SCFG_SPARECR3 0xfc508
+
+#define CCSR_GPIO1_GPDIR 0x130000
+#define CCSR_GPIO1_GPODR 0x130004
+#define CCSR_GPIO1_GPDAT 0x130008
+#define CCSR_GPIO1_GPDIR_29 0x4
+
+/* 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 void *dcsr_base, *ccsr_base, *pld_base;
+static int pld_flag;
+
+int fsl_dp_iomap(void)
+{
+ struct device_node *np;
+ const u32 *prop;
+ int ret = 0;
+ u64 ccsr_phy_addr, dcsr_phy_addr;
+
+ np = of_find_node_by_type(NULL, "soc");
+ if (!np) {
+ pr_err("%s: Can't find the node of \"soc\"\n", __func__);
+ ret = -EINVAL;
+ goto ccsr_err;
+ }
+ prop = of_get_property(np, "ranges", NULL);
+ if (!prop) {
+ pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
+ of_node_put(np);
+ ret = -EINVAL;
+ goto ccsr_err;
+ }
+ ccsr_phy_addr = of_translate_address(np, prop + 1);
+ ccsr_base = ioremap((phys_addr_t)ccsr_phy_addr, SIZE_2MB);
+ of_node_put(np);
+ if (!ccsr_base) {
+ ret = -ENOMEM;
+ goto ccsr_err;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,dcsr");
+ if (!np) {
+ pr_err("%s: Can't find the node of \"fsl,dcsr\"\n", __func__);
+ ret = -EINVAL;
+ goto dcsr_err;
+ }
+ prop = of_get_property(np, "ranges", NULL);
+ if (!prop) {
+ pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
+ of_node_put(np);
+ ret = -EINVAL;
+ goto dcsr_err;
+ }
+ dcsr_phy_addr = of_translate_address(np, prop + 1);
+ dcsr_base = ioremap((phys_addr_t)dcsr_phy_addr, SIZE_1MB);
+ of_node_put(np);
+ if (!dcsr_base) {
+ ret = -ENOMEM;
+ goto dcsr_err;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,fpga-qixis");
+ if (np) {
+ pld_flag = FPGA_FLAG;
+ } else {
+ np = of_find_compatible_node(NULL, NULL, "fsl,p104xrdb-cpld");
+ if (np) {
+ pld_flag = CPLD_FLAG;
+ } else {
+ pr_err("%s: Can't find the FPGA/CPLD node\n",
+ __func__);
+ ret = -EINVAL;
+ goto pld_err;
+ }
+ }
+ pld_base = of_iomap(np, 0);
+ of_node_put(np);
+
+ return 0;
+
+pld_err:
+ iounmap(dcsr_base);
+dcsr_err:
+ iounmap(ccsr_base);
+ccsr_err:
+ ccsr_base = NULL;
+ dcsr_base = NULL;
+ pld_base = NULL;
+ return ret;
+}
+
+void fsl_dp_iounmap(void)
+{
+ if (dcsr_base) {
+ iounmap(dcsr_base);
+ dcsr_base = NULL;
+ }
+
+ if (ccsr_base) {
+ iounmap(ccsr_base);
+ ccsr_base = NULL;
+ }
+
+ if (pld_base) {
+ iounmap(pld_base);
+ pld_base = NULL;
+ }
+}
+
+static void fsl_dp_ddr_save(void *ccsr_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(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr);
+}
+
+static void fsl_dp_set_resume_pointer(void *ccsr_base)
+{
+ u32 resume_addr;
+
+ /* the bootloader will finally jump to this address to return kernel */
+#ifdef CONFIG_PPC32
+ resume_addr = (u32)(__pa(__entry_deep_sleep));
+#else
+ resume_addr = (u32)(__pa(*(u64 *)__entry_deep_sleep) & 0xffffffff);
+#endif
+
+ /* use the register SPARECR2 to save the resume address */
+ out_be32(ccsr_base + CCSR_SCFG_SPARECR2, resume_addr);
+
+}
+
+int fsl_enter_epu_deepsleep(void)
+{
+
+ fsl_dp_ddr_save(ccsr_base);
+
+ fsl_dp_set_resume_pointer(ccsr_base);
+
+ /* enable Warm Device Reset request. */
+ setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+ /* set GPIO1_29 as an output pin (not open-drain), and output 0 */
+ clrbits32(ccsr_base + CCSR_GPIO1_GPDAT, CCSR_GPIO1_GPDIR_29);
+ clrbits32(ccsr_base + CCSR_GPIO1_GPODR, CCSR_GPIO1_GPDIR_29);
+ setbits32(ccsr_base + CCSR_GPIO1_GPDIR, CCSR_GPIO1_GPDIR_29);
+
+ fsl_dp_fsm_setup(dcsr_base);
+
+ fsl_dp_enter_low(ccsr_base, dcsr_base, pld_base, pld_flag);
+
+ /* disable Warm Device Reset request */
+ clrbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
+
+ fsl_dp_fsm_clean(dcsr_base);
+
+ return 0;
+}
diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
index 915b13b..5f2c016 100644
--- a/arch/powerpc/platforms/85xx/qoriq_pm.c
+++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
@@ -20,6 +20,8 @@
#define FSL_SLEEP 0x1
#define FSL_DEEP_SLEEP 0x2
+int (*fsl_enter_deepsleep)(void);
+
/* specify the sleep state of the present platform */
int sleep_pm_state;
/* supported sleep modes by the present platform */
@@ -28,6 +30,7 @@ static unsigned int sleep_modes;
static int qoriq_suspend_enter(suspend_state_t state)
{
int ret = 0;
+ int cpu;
switch (state) {
case PM_SUSPEND_STANDBY:
@@ -39,6 +42,17 @@ static int qoriq_suspend_enter(suspend_state_t state)
break;
+ case PM_SUSPEND_MEM:
+
+ cpu = smp_processor_id();
+ qoriq_pm_ops->irq_mask(cpu);
+
+ ret = fsl_enter_deepsleep();
+
+ qoriq_pm_ops->irq_unmask(cpu);
+
+ break;
+
default:
ret = -EINVAL;
@@ -52,12 +66,30 @@ static int qoriq_suspend_valid(suspend_state_t state)
if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
return 1;
+ if (state == PM_SUSPEND_MEM && (sleep_modes & FSL_DEEP_SLEEP))
+ return 1;
+
return 0;
}
+static int qoriq_suspend_begin(suspend_state_t state)
+{
+ if (state == PM_SUSPEND_MEM)
+ return fsl_dp_iomap();
+
+ return 0;
+}
+
+static void qoriq_suspend_end(void)
+{
+ fsl_dp_iounmap();
+}
+
static const struct platform_suspend_ops qoriq_suspend_ops = {
.valid = qoriq_suspend_valid,
.enter = qoriq_suspend_enter,
+ .begin = qoriq_suspend_begin,
+ .end = qoriq_suspend_end,
};
static int __init qoriq_suspend_init(void)
@@ -71,6 +103,12 @@ static int __init qoriq_suspend_init(void)
if (np)
sleep_pm_state = PLAT_PM_LPM20;
+ np = of_find_compatible_node(NULL, NULL, "fsl,t1040-rcpm");
+ if (np) {
+ fsl_enter_deepsleep = fsl_enter_epu_deepsleep;
+ sleep_modes |= FSL_DEEP_SLEEP;
+ }
+
suspend_set_ops(&qoriq_suspend_ops);
return 0;
diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..95a5746
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,295 @@
+/*
+ * Implement the low level part of deep sleep
+ *
+ * Copyright 2014 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/booke_save_regs.h>
+#include <asm/mmu.h>
+
+#define FSLDELAY(count) \
+ li r3, (count)@l; \
+ slwi r3, r3, 10; \
+ mtctr r3; \
+101: nop; \
+ bdnz 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
+booke_regs_buffer:
+ .space REGS_BUFFER_SIZE
+
+ .section .txt
+ .align 6
+
+_GLOBAL(fsl_dp_enter_low)
+deepsleep_start:
+ LOAD_REG_ADDR(r9, buf_tmp)
+ PPC_STL r3, 0(r9)
+ PPC_STL r4, 8(r9)
+ PPC_STL r5, 16(r9)
+ PPC_STL r6, 24(r9)
+
+ LOAD_REG_ADDR(r3, booke_regs_buffer)
+ /* save the return address */
+ mflr r5
+ PPC_STL r5, SR_LR(r3)
+ mfmsr r5
+ PPC_STL r5, SR_MSR(r3)
+ li r4, DEEPSLEEP_FLAG
+ bl booke_cpu_state_save
+
+ LOAD_REG_ADDR(r9, buf_tmp)
+ PPC_LL r31, 0(r9)
+ PPC_LL r30, 8(r9)
+ PPC_LL r29, 16(r9)
+ PPC_LL r28, 24(r9)
+
+ /* flush caches */
+ LOAD_REG_ADDR(r3, cur_cpu_spec)
+ PPC_LL r3, 0(r3)
+ PPC_LL r3, CPU_FLUSH_CACHES(r3)
+ PPC_LCMPI 0, r3, 0
+ beq 6f
+#ifdef CONFIG_PPC64
+ PPC_LL r3, 0(r3)
+#endif
+ mtctr r3
+ bctrl
+6:
+#define CPC_OFFSET 0x10000
+ mr r3, r31
+ addis r3, r3, CPC_OFFSET@h
+ bl fsl_flush_cpc_cache
+
+ LOAD_REG_ADDR(r8, deepsleep_start)
+ LOAD_REG_ADDR(r9, deepsleep_end)
+
+ /* prefecth TLB */
+#define CCSR_GPIO1_GPDAT 0x130008
+#define CCSR_GPIO1_GPDAT_29 0x4
+ LOAD_REG_IMMEDIATE(r11, CCSR_GPIO1_GPDAT)
+ add r11, r31, r11
+ lwz r10, 0(r11)
+
+#define CCSR_RCPM_PCPH15SETR 0xe20b4
+#define CCSR_RCPM_PCPH15SETR_CORE0 0x1
+ LOAD_REG_IMMEDIATE(r12, CCSR_RCPM_PCPH15SETR)
+ add r12, r31, r12
+ lwz r10, 0(r12)
+
+#define CCSR_DDR_SDRAM_CFG_2 0x8114
+#define CCSR_DDR_SDRAM_CFG_2_FRC_SR 0x80000000
+ LOAD_REG_IMMEDIATE(r13, CCSR_DDR_SDRAM_CFG_2)
+ add r13, r31, r13
+ lwz r10, 0(r13)
+
+#define DCSR_EPU_EPGCR 0x000
+#define DCSR_EPU_EPGCR_GCE 0x80000000
+ li r14, DCSR_EPU_EPGCR
+ add r14, r30, r14
+ lwz r10, 0(r14)
+
+#define DCSR_EPU_EPECR15 0x33C
+#define DCSR_EPU_EPECR15_IC0 0x80000000
+ li r15, DCSR_EPU_EPECR15
+ add r15, r30, r15
+ lwz r10, 0(r15)
+
+#define CCSR_SCFG_QMCRDTRSTCR 0xfc40c
+#define CCSR_SCFG_QMCRDTRSTCR_CRDTRST 0x80000000
+ LOAD_REG_IMMEDIATE(r16, CCSR_SCFG_QMCRDTRSTCR)
+ add r16, r31, r16
+ lwz r10, 0(r16)
+
+/*
+ * There are two kind of register maps, one for CPLD and the other for FPGA
+ */
+#define CPLD_MISCCSR 0x17
+#define CPLD_MISCCSR_SLEEPEN 0x40
+#define QIXIS_PWR_CTL2 0x21
+#define QIXIS_PWR_CTL2_PCTL 0x2
+ PPC_LCMPI 0, r28, FPGA_FLAG
+ beq 20f
+ addi r29, r29, CPLD_MISCCSR
+20:
+ addi r29, r29, QIXIS_PWR_CTL2
+ lbz r10, 0(r29)
+
+ /* prefecth code to cache so that executing code after disable DDR */
+1: lwz r3, 0(r8)
+ addi r8, r8, 4
+ cmpw r8, r9
+ blt 1b
+ msync
+
+ FSL_DIS_ALL_IRQ
+
+ /*
+ * Place DDR controller in self refresh mode.
+ * From here on, DDR can't be access any more.
+ */
+ lwz r10, 0(r13)
+ oris r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
+ stw r10, 0(r13)
+
+ /* can't call udelay() here, so use a macro to delay */
+ FSLDELAY(50)
+
+ /*
+ * Enable deep sleep signals by write external CPLD/FPGA register.
+ * The bootloader will disable them when wakeup from deep sleep.
+ */
+ lbz r10, 0(r29)
+ PPC_LCMPI 0, r28, FPGA_FLAG
+ beq 22f
+ ori r10, r10, CPLD_MISCCSR_SLEEPEN
+22:
+ ori r10, r10, QIXIS_PWR_CTL2_PCTL
+ stb r10, 0(r29)
+
+ /*
+ * 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)
+
+ FSLDELAY(10)
+
+ /* Clear the QMan CITI Credits */
+ lwz r10, 0(r16)
+ oris r10, r10, CCSR_SCFG_QMCRDTRSTCR_CRDTRST@h
+ stw r10, 0(r16)
+
+ /* Enable all EPU Counters */
+ li r10, 0
+ oris r10, r10, DCSR_EPU_EPGCR_GCE@h
+ stw 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)
+
+ /* 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:
+
+#ifdef CONFIG_PPC32
+_GLOBAL(fsl_deepsleep_resume)
+ /* disable interrupts */
+ FSL_DIS_ALL_IRQ
+
+ 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 r0, 0
+3: mr r3, r0
+ bl loadcam_entry
+ addi r0, r0, 1
+ bdnz 3b
+
+ /* restore cpu registers */
+ LOAD_REG_ADDR(r3, booke_regs_buffer)
+ li r4, DEEPSLEEP_FLAG
+ bl booke_cpu_state_restore
+
+ LOAD_REG_ADDR(r3, booke_regs_buffer)
+ lwz r4, SR_MSR(r3)
+ mtmsr r4
+ lwz r4, SR_LR(r3)
+ mtlr r4
+
+ blr
+
+#else /* CONFIG_PPC32 */
+
+_GLOBAL(__entry_deep_sleep)
+ /* 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, booke_regs_buffer)
+ li r4, DEEPSLEEP_FLAG
+ bl booke_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, booke_regs_buffer)
+ ld r4, SR_MSR(r3)
+ mtmsr r4
+ ld r4, SR_LR(r3)
+ mtlr r4
+
+ blr
+
+#endif /* CONFIG_PPC32 */
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index eb83a30..7351c40 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -67,7 +67,14 @@ extern const struct fsl_pm_ops *qoriq_pm_ops;
#define PLAT_PM_SLEEP 20
#define PLAT_PM_LPM20 30
+extern int fsl_dp_iomap(void);
+extern void fsl_dp_iounmap(void);
+
extern int fsl_rcpm_init(void);
+extern int fsl_enter_epu_deepsleep(void);
+extern void fsl_dp_enter_low(void *ccsr_base, void *dcsr_base,
+ void *pld_base, int pld_flag);
+extern void __entry_deep_sleep(void);
extern void fsl_dp_fsm_setup(void *dcsr_base);
extern void fsl_dp_fsm_clean(void *dcsr_base);
--
1.7.3
^ permalink raw reply related [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-07 4:58 ` [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040 Chenhui Zhao
@ 2014-03-12 1:10 ` Scott Wood
2014-03-12 5:57 ` Kevin Hao
2014-03-12 10:40 ` Chenhui Zhao
0 siblings, 2 replies; 50+ messages in thread
From: Scott Wood @ 2014-03-12 1:10 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> From: Zhao Chenhui <chenhui.zhao@freescale.com>
>
> T1040 supports 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 will be prefetched.
>
> Due to the different initialization code between 32-bit and 64-bit, they
> have seperate resume entry and precedure.
>
> The feature supports 32-bit and 64-bit kernel mode.
>
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> ---
> arch/powerpc/include/asm/booke_save_regs.h | 3 +
> arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
> arch/powerpc/kernel/head_fsl_booke.S | 30 +++
> arch/powerpc/platforms/85xx/Makefile | 2 +-
> arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
> arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
> arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
> arch/powerpc/sysdev/fsl_soc.h | 7 +
> 8 files changed, 592 insertions(+), 1 deletions(-)
> create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> create mode 100644 arch/powerpc/platforms/85xx/sleep.S
>
> diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> index 87c357a..37c1f6c 100644
> --- a/arch/powerpc/include/asm/booke_save_regs.h
> +++ b/arch/powerpc/include/asm/booke_save_regs.h
> @@ -88,6 +88,9 @@
> #define HIBERNATION_FLAG 1
> #define DEEPSLEEP_FLAG 2
>
> +#define CPLD_FLAG 1
> +#define FPGA_FLAG 2
What is this?
> #ifndef __ASSEMBLY__
> extern void booke_cpu_state_save(void *buf, int type);
> extern void *booke_cpu_state_restore(void *buf, int type);
> diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> index e59d6de..ea9bc28 100644
> --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> @@ -318,6 +318,23 @@ flush_backside_L2_cache:
> 2:
> blr
>
> +#define CPC_CPCCSR0 0x0
> +#define CPC_CPCCSR0_CPCFL 0x800
This is supposed to be CPU setup, not platform setup.
> +/* r3 : the base address of CPC */
> +_GLOBAL(fsl_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
> +
> _GLOBAL(__flush_caches_e500v2)
I'm not sure that this belongs here either.
> mflr r0
> bl flush_dcache_L1
> diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> index 20204fe..3285752 100644
> --- a/arch/powerpc/kernel/head_fsl_booke.S
> +++ b/arch/powerpc/kernel/head_fsl_booke.S
> @@ -162,6 +162,19 @@ _ENTRY(__early_start)
> #include "fsl_booke_entry_mapping.S"
> #undef ENTRY_MAPPING_BOOT_SETUP
>
> +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> + /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
> + LOAD_REG_ADDR(r4, deep_sleep_flag)
> + lwz r3, 0(r4)
> + cmpwi r3, 0
> + beq 11f
> + /* clear deep_sleep_flag */
> + li r3, 0
> + stw r3, 0(r4)
> + b fsl_deepsleep_resume
> +11:
> +#endif
Why do you come in via the normal kernel entry, versus specifying a
direct entry point for deep sleep resume? How does U-Boot even know
what the normal entry is when resuming?
Be careful of the "beq set_ivor" in the CONFIG_RELOCATABLE section
above. Also you probably don't want the relocation code to run again
when resuming.
> +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> +_ENTRY(__entry_deep_sleep)
> +/*
> + * Bootloader will jump to here when resuming from deep sleep.
> + * After executing the init code in fsl_booke_entry_mapping.S,
> + * will jump to the real resume entry.
> + */
> + li r8, 1
> + bl 12f
> +12: mflr r9
> + addi r9, r9, (deep_sleep_flag - 12b)
> + stw r8, 0(r9)
> + b __early_start
> +deep_sleep_flag:
> + .long 0
> +#endif
It's a bit ambiguous to say "entry_deep_sleep" when it's resuming rather
than entering...
So you do have a special entry point. Why do you go to __early_start
only to quickly test a flag and branch away?
> diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> index 7fae817..9a4ea86 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -3,7 +3,7 @@
> #
> obj-$(CONFIG_SMP) += smp.o
> ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
> -obj-$(CONFIG_SUSPEND) += qoriq_pm.o
> +obj-$(CONFIG_SUSPEND) += qoriq_pm.o deepsleep.o sleep.o
> endif
>
> 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..ddd7185
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/deepsleep.c
> @@ -0,0 +1,201 @@
> +/*
> + * Support deep sleep feature
AFAICT this supports deep sleep on T1040, not on all 85xx that has it.
> + *
> + * Copyright 2014 Freescale Semiconductor Inc.
> + *
> + * Author: Chenhui Zhao <chenhui.zhao@freescale.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/of_platform.h>
> +#include <linux/of_address.h>
> +#include <asm/machdep.h>
> +#include <sysdev/fsl_soc.h>
> +#include <asm/booke_save_regs.h>
> +
> +#define SIZE_1MB 0x100000
> +#define SIZE_2MB 0x200000
> +
> +#define CCSR_SCFG_DPSLPCR 0xfc000
> +#define CCSR_SCFG_DPSLPCR_WDRR_EN 0x1
> +#define CCSR_SCFG_SPARECR2 0xfc504
> +#define CCSR_SCFG_SPARECR3 0xfc508
> +
> +#define CCSR_GPIO1_GPDIR 0x130000
> +#define CCSR_GPIO1_GPODR 0x130004
> +#define CCSR_GPIO1_GPDAT 0x130008
> +#define CCSR_GPIO1_GPDIR_29 0x4
> +
> +/* 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 void *dcsr_base, *ccsr_base, *pld_base;
> +static int pld_flag;
> +
> +int fsl_dp_iomap(void)
> +{
> + struct device_node *np;
> + const u32 *prop;
> + int ret = 0;
> + u64 ccsr_phy_addr, dcsr_phy_addr;
> +
> + np = of_find_node_by_type(NULL, "soc");
> + if (!np) {
> + pr_err("%s: Can't find the node of \"soc\"\n", __func__);
> + ret = -EINVAL;
> + goto ccsr_err;
> + }
> + prop = of_get_property(np, "ranges", NULL);
> + if (!prop) {
> + pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
> + of_node_put(np);
> + ret = -EINVAL;
> + goto ccsr_err;
> + }
Use get_immrbase(), or better use specific nodes in the device tree.
> + ccsr_phy_addr = of_translate_address(np, prop + 1);
> + ccsr_base = ioremap((phys_addr_t)ccsr_phy_addr, SIZE_2MB);
> + of_node_put(np);
> + if (!ccsr_base) {
> + ret = -ENOMEM;
> + goto ccsr_err;
> + }
Unnecessary cast.
Why 2 MiB?
> + np = of_find_compatible_node(NULL, NULL, "fsl,dcsr");
> + if (!np) {
> + pr_err("%s: Can't find the node of \"fsl,dcsr\"\n", __func__);
> + ret = -EINVAL;
> + goto dcsr_err;
> + }
> + prop = of_get_property(np, "ranges", NULL);
> + if (!prop) {
> + pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
> + of_node_put(np);
> + ret = -EINVAL;
> + goto dcsr_err;
> + }
> + dcsr_phy_addr = of_translate_address(np, prop + 1);
> + dcsr_base = ioremap((phys_addr_t)dcsr_phy_addr, SIZE_1MB);
> + of_node_put(np);
> + if (!dcsr_base) {
> + ret = -ENOMEM;
> + goto dcsr_err;
> + }
If you must do this, add a helper to get the dcsr base -- but do we not
already have dcsr subnodes for what you are using?
> +
> + np = of_find_compatible_node(NULL, NULL, "fsl,fpga-qixis");
> + if (np) {
> + pld_flag = FPGA_FLAG;
> + } else {
> + np = of_find_compatible_node(NULL, NULL, "fsl,p104xrdb-cpld");
> + if (np) {
> + pld_flag = CPLD_FLAG;
> + } else {
> + pr_err("%s: Can't find the FPGA/CPLD node\n",
> + __func__);
> + ret = -EINVAL;
> + goto pld_err;
> + }
> + }
OK, so this file isn't even specific to T1040 -- it's specific to our
reference boards?
> +static void fsl_dp_ddr_save(void *ccsr_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);
That assumption may break with a relocatable kernel.
> +
> +}
> +
> +int fsl_enter_epu_deepsleep(void)
> +{
> +
> +
No blank lines at begin/end of function.
> diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
> index 915b13b..5f2c016 100644
> --- a/arch/powerpc/platforms/85xx/qoriq_pm.c
> +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
> @@ -20,6 +20,8 @@
> #define FSL_SLEEP 0x1
> #define FSL_DEEP_SLEEP 0x2
>
> +int (*fsl_enter_deepsleep)(void);
> +
> /* specify the sleep state of the present platform */
> int sleep_pm_state;
> /* supported sleep modes by the present platform */
> @@ -28,6 +30,7 @@ static unsigned int sleep_modes;
> static int qoriq_suspend_enter(suspend_state_t state)
> {
> int ret = 0;
> + int cpu;
>
> switch (state) {
> case PM_SUSPEND_STANDBY:
> @@ -39,6 +42,17 @@ static int qoriq_suspend_enter(suspend_state_t state)
>
> break;
>
> + case PM_SUSPEND_MEM:
> +
> + cpu = smp_processor_id();
> + qoriq_pm_ops->irq_mask(cpu);
> +
> + ret = fsl_enter_deepsleep();
> +
> + qoriq_pm_ops->irq_unmask(cpu);
> +
> + break;
> +
> default:
> ret = -EINVAL;
>
> @@ -52,12 +66,30 @@ static int qoriq_suspend_valid(suspend_state_t state)
> if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
> return 1;
>
> + if (state == PM_SUSPEND_MEM && (sleep_modes & FSL_DEEP_SLEEP))
> + return 1;
> +
> return 0;
> }
>
> +static int qoriq_suspend_begin(suspend_state_t state)
> +{
> + if (state == PM_SUSPEND_MEM)
> + return fsl_dp_iomap();
> +
> + return 0;
> +}
> +
> +static void qoriq_suspend_end(void)
> +{
> + fsl_dp_iounmap();
> +}
> +
> static const struct platform_suspend_ops qoriq_suspend_ops = {
> .valid = qoriq_suspend_valid,
> .enter = qoriq_suspend_enter,
> + .begin = qoriq_suspend_begin,
> + .end = qoriq_suspend_end,
> };
>
> static int __init qoriq_suspend_init(void)
> @@ -71,6 +103,12 @@ static int __init qoriq_suspend_init(void)
> if (np)
> sleep_pm_state = PLAT_PM_LPM20;
>
> + np = of_find_compatible_node(NULL, NULL, "fsl,t1040-rcpm");
> + if (np) {
> + fsl_enter_deepsleep = fsl_enter_epu_deepsleep;
> + sleep_modes |= FSL_DEEP_SLEEP;
> + }
> +
> suspend_set_ops(&qoriq_suspend_ops);
>
> return 0;
> diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
> new file mode 100644
> index 0000000..95a5746
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/sleep.S
> @@ -0,0 +1,295 @@
> +/*
> + * Implement the low level part of deep sleep
> + *
> + * Copyright 2014 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/booke_save_regs.h>
> +#include <asm/mmu.h>
> +
> +#define FSLDELAY(count) \
> + li r3, (count)@l; \
> + slwi r3, r3, 10; \
> + mtctr r3; \
> +101: nop; \
> + bdnz 101b;
You don't need a namespace prefix on local macros in a non-header file.
Is the timebase stopped where you're calling this from?
> +#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
> +booke_regs_buffer:
> + .space REGS_BUFFER_SIZE
> +
> + .section .txt
> + .align 6
> +
> +_GLOBAL(fsl_dp_enter_low)
> +deepsleep_start:
> + LOAD_REG_ADDR(r9, buf_tmp)
> + PPC_STL r3, 0(r9)
> + PPC_STL r4, 8(r9)
> + PPC_STL r5, 16(r9)
> + PPC_STL r6, 24(r9)
> +
> + LOAD_REG_ADDR(r3, booke_regs_buffer)
> + /* save the return address */
> + mflr r5
> + PPC_STL r5, SR_LR(r3)
> + mfmsr r5
> + PPC_STL r5, SR_MSR(r3)
> + li r4, DEEPSLEEP_FLAG
> + bl booke_cpu_state_save
> +
> + LOAD_REG_ADDR(r9, buf_tmp)
> + PPC_LL r31, 0(r9)
> + PPC_LL r30, 8(r9)
> + PPC_LL r29, 16(r9)
> + PPC_LL r28, 24(r9)
> +
> + /* flush caches */
> + LOAD_REG_ADDR(r3, cur_cpu_spec)
> + PPC_LL r3, 0(r3)
> + PPC_LL r3, CPU_FLUSH_CACHES(r3)
> + PPC_LCMPI 0, r3, 0
> + beq 6f
> +#ifdef CONFIG_PPC64
> + PPC_LL r3, 0(r3)
> +#endif
> + mtctr r3
> + bctrl
> +6:
> +#define CPC_OFFSET 0x10000
> + mr r3, r31
> + addis r3, r3, CPC_OFFSET@h
> + bl fsl_flush_cpc_cache
> +
> + LOAD_REG_ADDR(r8, deepsleep_start)
> + LOAD_REG_ADDR(r9, deepsleep_end)
> +
> + /* prefecth TLB */
> +#define CCSR_GPIO1_GPDAT 0x130008
> +#define CCSR_GPIO1_GPDAT_29 0x4
> + LOAD_REG_IMMEDIATE(r11, CCSR_GPIO1_GPDAT)
> + add r11, r31, r11
> + lwz r10, 0(r11)
> +
> +#define CCSR_RCPM_PCPH15SETR 0xe20b4
> +#define CCSR_RCPM_PCPH15SETR_CORE0 0x1
> + LOAD_REG_IMMEDIATE(r12, CCSR_RCPM_PCPH15SETR)
> + add r12, r31, r12
> + lwz r10, 0(r12)
> +
> +#define CCSR_DDR_SDRAM_CFG_2 0x8114
> +#define CCSR_DDR_SDRAM_CFG_2_FRC_SR 0x80000000
> + LOAD_REG_IMMEDIATE(r13, CCSR_DDR_SDRAM_CFG_2)
> + add r13, r31, r13
> + lwz r10, 0(r13)
> +
> +#define DCSR_EPU_EPGCR 0x000
> +#define DCSR_EPU_EPGCR_GCE 0x80000000
> + li r14, DCSR_EPU_EPGCR
> + add r14, r30, r14
> + lwz r10, 0(r14)
> +
> +#define DCSR_EPU_EPECR15 0x33C
> +#define DCSR_EPU_EPECR15_IC0 0x80000000
> + li r15, DCSR_EPU_EPECR15
> + add r15, r30, r15
> + lwz r10, 0(r15)
> +
> +#define CCSR_SCFG_QMCRDTRSTCR 0xfc40c
> +#define CCSR_SCFG_QMCRDTRSTCR_CRDTRST 0x80000000
> + LOAD_REG_IMMEDIATE(r16, CCSR_SCFG_QMCRDTRSTCR)
> + add r16, r31, r16
> + lwz r10, 0(r16)
> +
> +/*
> + * There are two kind of register maps, one for CPLD and the other for FPGA
> + */
> +#define CPLD_MISCCSR 0x17
> +#define CPLD_MISCCSR_SLEEPEN 0x40
> +#define QIXIS_PWR_CTL2 0x21
> +#define QIXIS_PWR_CTL2_PCTL 0x2
> + PPC_LCMPI 0, r28, FPGA_FLAG
> + beq 20f
> + addi r29, r29, CPLD_MISCCSR
> +20:
> + addi r29, r29, QIXIS_PWR_CTL2
> + lbz r10, 0(r29)
Again, this is not marked as a board-specific file. How do you expect
customers to adapt this mechanism to their boards?
> +
> + /* prefecth code to cache so that executing code after disable DDR */
> +1: lwz r3, 0(r8)
> + addi r8, r8, 4
> + cmpw r8, r9
> + blt 1b
> + msync
Instructions don't execute from dcache... I guess you're assuming it
will allocate in, and stay in, L2/CPC. It'd be safer to lock those
cache lines in icache, or copy the code to SRAM.
> + FSL_DIS_ALL_IRQ
> +
> + /*
> + * Place DDR controller in self refresh mode.
> + * From here on, DDR can't be access any more.
> + */
> + lwz r10, 0(r13)
> + oris r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
> + stw r10, 0(r13)
> +
> + /* can't call udelay() here, so use a macro to delay */
> + FSLDELAY(50)
A timebase loop doesn't require accessing DDR.
You also probably want to do a "sync, readback, data dependency, isync"
sequence to make sure that the store has hit CCSR before you begin your
delay (or is a delay required at all if you do that?).
> + /*
> + * Enable deep sleep signals by write external CPLD/FPGA register.
> + * The bootloader will disable them when wakeup from deep sleep.
> + */
> + lbz r10, 0(r29)
> + PPC_LCMPI 0, r28, FPGA_FLAG
> + beq 22f
> + ori r10, r10, CPLD_MISCCSR_SLEEPEN
> +22:
> + ori r10, r10, QIXIS_PWR_CTL2_PCTL
> + stb r10, 0(r29)
> +
> + /*
> + * 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)
> +
> + FSLDELAY(10)
> +
> + /* Clear the QMan CITI Credits */
> + lwz r10, 0(r16)
> + oris r10, r10, CCSR_SCFG_QMCRDTRSTCR_CRDTRST@h
> + stw r10, 0(r16)
> +
> + /* Enable all EPU Counters */
> + li r10, 0
> + oris r10, r10, DCSR_EPU_EPGCR_GCE@h
> + stw 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)
> +
> + /* put Core0 in PH15 mode, trigger EPU FSM */
> + lwz r10, 0(r12)
> + ori r10, r10, CCSR_RCPM_PCPH15SETR_CORE0
> + stw r10, 0(r12)
Shouldn't there be a sync to ensure that the previous I/O happens before
the final store to enter PH15?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-12 1:10 ` Scott Wood
@ 2014-03-12 5:57 ` Kevin Hao
2014-03-12 17:43 ` Scott Wood
2014-03-12 10:40 ` Chenhui Zhao
1 sibling, 1 reply; 50+ messages in thread
From: Kevin Hao @ 2014-03-12 5:57 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1927 bytes --]
On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> > + FSL_DIS_ALL_IRQ
> > +
> > + /*
> > + * Place DDR controller in self refresh mode.
> > + * From here on, DDR can't be access any more.
> > + */
> > + lwz r10, 0(r13)
> > + oris r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
> > + stw r10, 0(r13)
> > +
> > + /* can't call udelay() here, so use a macro to delay */
> > + FSLDELAY(50)
>
> A timebase loop doesn't require accessing DDR.
>
> You also probably want to do a "sync, readback, data dependency, isync"
> sequence to make sure that the store has hit CCSR before you begin your
> delay (or is a delay required at all if you do that?).
Shouldn't we use "readback, sync" here? The following is quoted form t4240RM:
To guarantee that the results of any sequence of writes to configuration
registers are in effect, the final configuration register write should be
immediately followed by a read of the same register, and that should be
followed by a SYNC instruction. Then accesses can safely be made to memory
regions affected by the configuration register write.
> > +
> > + /* Enable SCU15 to trigger on RCPM Concentrator 0 */
> > + lwz r10, 0(r15)
> > + oris r10, r10, DCSR_EPU_EPECR15_IC0@h
> > + stw 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)
>
> Shouldn't there be a sync to ensure that the previous I/O happens before
> the final store to enter PH15?
Do we really need a sync here? According to the PowerISA, the above stores
should be performed in program order.
If two Store instructions or two Load instructions
specify storage locations that are both Caching
Inhibited and Guarded, the corresponding storage
accesses are performed in program order with
respect to any processor or mechanism.
Thanks,
Kevin
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-12 5:57 ` Kevin Hao
@ 2014-03-12 17:43 ` Scott Wood
2014-03-13 7:46 ` Kevin Hao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-12 17:43 UTC (permalink / raw)
To: Kevin Hao; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
On Wed, 2014-03-12 at 13:57 +0800, Kevin Hao wrote:
> On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> > > + FSL_DIS_ALL_IRQ
> > > +
> > > + /*
> > > + * Place DDR controller in self refresh mode.
> > > + * From here on, DDR can't be access any more.
> > > + */
> > > + lwz r10, 0(r13)
> > > + oris r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
> > > + stw r10, 0(r13)
> > > +
> > > + /* can't call udelay() here, so use a macro to delay */
> > > + FSLDELAY(50)
> >
> > A timebase loop doesn't require accessing DDR.
> >
> > You also probably want to do a "sync, readback, data dependency, isync"
> > sequence to make sure that the store has hit CCSR before you begin your
> > delay (or is a delay required at all if you do that?).
>
> Shouldn't we use "readback, sync" here? The following is quoted form t4240RM:
> To guarantee that the results of any sequence of writes to configuration
> registers are in effect, the final configuration register write should be
> immediately followed by a read of the same register, and that should be
> followed by a SYNC instruction. Then accesses can safely be made to memory
> regions affected by the configuration register write.
I agree that the sync before the readback is probably not necessary,
since transactions to the same address should already be ordered.
A sync after the readback helps if you're trying to order the readback
with subsequent memory accesses, though in that case wouldn't a sync
alone (no readback) be adequate? Though maybe not always -- see the
comment near the end of fsl_elbc_write_buf() in
drivers/mtd/nand_fsl_elbc.c. I guess the readback does more than just
make sure the device has seen the write, ensuring that the device has
finished the transaction to the point of acting on another one.
The data dependency plus isync sequence, which is done by the normal I/O
accessors used from C code, orders the readback versus all future
instructions (not just I/O). The delay loop is not I/O.
> > > + /* Enable SCU15 to trigger on RCPM Concentrator 0 */
> > > + lwz r10, 0(r15)
> > > + oris r10, r10, DCSR_EPU_EPECR15_IC0@h
> > > + stw 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)
> >
> > Shouldn't there be a sync to ensure that the previous I/O happens before
> > the final store to enter PH15?
>
> Do we really need a sync here? According to the PowerISA, the above stores
> should be performed in program order.
> If two Store instructions or two Load instructions
> specify storage locations that are both Caching
> Inhibited and Guarded, the corresponding storage
> accesses are performed in program order with
> respect to any processor or mechanism.
OK, wasn't aware of that.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-12 17:43 ` Scott Wood
@ 2014-03-13 7:46 ` Kevin Hao
2014-03-14 22:26 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Kevin Hao @ 2014-03-13 7:46 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1829 bytes --]
On Wed, Mar 12, 2014 at 12:43:05PM -0500, Scott Wood wrote:
> > Shouldn't we use "readback, sync" here? The following is quoted form t4240RM:
> > To guarantee that the results of any sequence of writes to configuration
> > registers are in effect, the final configuration register write should be
> > immediately followed by a read of the same register, and that should be
> > followed by a SYNC instruction. Then accesses can safely be made to memory
> > regions affected by the configuration register write.
>
> I agree that the sync before the readback is probably not necessary,
> since transactions to the same address should already be ordered.
>
> A sync after the readback helps if you're trying to order the readback
> with subsequent memory accesses, though in that case wouldn't a sync
> alone (no readback) be adequate?
No, we don't just want to order the subsequent memory access here.
The 'write, readback, sync' is the required sequence if we want to make
sure that the writing to CCSR register does really take effect.
> Though maybe not always -- see the
> comment near the end of fsl_elbc_write_buf() in
> drivers/mtd/nand_fsl_elbc.c. I guess the readback does more than just
> make sure the device has seen the write, ensuring that the device has
> finished the transaction to the point of acting on another one.
Agree.
>
> The data dependency plus isync sequence, which is done by the normal I/O
> accessors used from C code, orders the readback versus all future
> instructions (not just I/O). The delay loop is not I/O.
According to the PowerISA, the sequence 'load, date dependency, isync' only
order the load accesses. So if we want to order all the storage access as well
as execution synchronization, we should choose sync here.
Thanks,
Kevin
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-13 7:46 ` Kevin Hao
@ 2014-03-14 22:26 ` Scott Wood
2014-03-16 4:58 ` Kevin Hao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-14 22:26 UTC (permalink / raw)
To: Kevin Hao; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
On Thu, 2014-03-13 at 15:46 +0800, Kevin Hao wrote:
> On Wed, Mar 12, 2014 at 12:43:05PM -0500, Scott Wood wrote:
> > > Shouldn't we use "readback, sync" here? The following is quoted form t4240RM:
> > > To guarantee that the results of any sequence of writes to configuration
> > > registers are in effect, the final configuration register write should be
> > > immediately followed by a read of the same register, and that should be
> > > followed by a SYNC instruction. Then accesses can safely be made to memory
> > > regions affected by the configuration register write.
> >
> > I agree that the sync before the readback is probably not necessary,
> > since transactions to the same address should already be ordered.
> >
> > A sync after the readback helps if you're trying to order the readback
> > with subsequent memory accesses, though in that case wouldn't a sync
> > alone (no readback) be adequate?
>
> No, we don't just want to order the subsequent memory access here.
> The 'write, readback, sync' is the required sequence if we want to make
> sure that the writing to CCSR register does really take effect.
>
> > Though maybe not always -- see the
> > comment near the end of fsl_elbc_write_buf() in
> > drivers/mtd/nand_fsl_elbc.c. I guess the readback does more than just
> > make sure the device has seen the write, ensuring that the device has
> > finished the transaction to the point of acting on another one.
>
> Agree.
>
> >
> > The data dependency plus isync sequence, which is done by the normal I/O
> > accessors used from C code, orders the readback versus all future
> > instructions (not just I/O). The delay loop is not I/O.
>
> According to the PowerISA, the sequence 'load, date dependency, isync' only
> order the load accesses.
The point is to order the delay loop after the load, not to order
storage versus storage.
This is a sequence we're already using on all of our I/O loads
(excluding accesses like in this patch that don't use the standard
accessors). I'm confident that it works even if it's not
architecturally guaranteed. I'm not sure that there exists a clear
architectural way of synchronizing non-storage instructions relative to
storage instructions.
Given that isync is documented as preventing any execution of
instructions after the isync until all previous instructions complete,
it doesn't seem to make sense for the architecture to explicitly talk
about loads (as opposed to any other instruction) following a load,
dependent conditional branch, isync sequence.
> So if we want to order all the storage access as well
> as execution synchronization, we should choose sync here.
Do we need execution synchronization or context synchronization?
The t4240 RM section that talks about a readback and a sync is in the
context of subsequent memory operations ("Then accesses can safely be
made to memory regions affected..."), not arbitrary instructions. There
are also a couple other places in the RM where isync is recommended
instead (when setting LAWs or CCSRBAR), even though those also only
involve memory accesses.
In any case, this is not performance critical and thus it's better to
oversynchronize than undersynchronize.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-14 22:26 ` Scott Wood
@ 2014-03-16 4:58 ` Kevin Hao
2014-03-18 23:18 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Kevin Hao @ 2014-03-16 4:58 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 6201 bytes --]
On Fri, Mar 14, 2014 at 05:26:27PM -0500, Scott Wood wrote:
> On Thu, 2014-03-13 at 15:46 +0800, Kevin Hao wrote:
> > On Wed, Mar 12, 2014 at 12:43:05PM -0500, Scott Wood wrote:
> > > > Shouldn't we use "readback, sync" here? The following is quoted form t4240RM:
> > > > To guarantee that the results of any sequence of writes to configuration
> > > > registers are in effect, the final configuration register write should be
> > > > immediately followed by a read of the same register, and that should be
> > > > followed by a SYNC instruction. Then accesses can safely be made to memory
> > > > regions affected by the configuration register write.
> > >
> > > I agree that the sync before the readback is probably not necessary,
> > > since transactions to the same address should already be ordered.
> > >
> > > A sync after the readback helps if you're trying to order the readback
> > > with subsequent memory accesses, though in that case wouldn't a sync
> > > alone (no readback) be adequate?
> >
> > No, we don't just want to order the subsequent memory access here.
> > The 'write, readback, sync' is the required sequence if we want to make
> > sure that the writing to CCSR register does really take effect.
> >
> > > Though maybe not always -- see the
> > > comment near the end of fsl_elbc_write_buf() in
> > > drivers/mtd/nand_fsl_elbc.c. I guess the readback does more than just
> > > make sure the device has seen the write, ensuring that the device has
> > > finished the transaction to the point of acting on another one.
> >
> > Agree.
> >
> > >
> > > The data dependency plus isync sequence, which is done by the normal I/O
> > > accessors used from C code, orders the readback versus all future
> > > instructions (not just I/O). The delay loop is not I/O.
> >
> > According to the PowerISA, the sequence 'load, date dependency, isync' only
> > order the load accesses.
>
> The point is to order the delay loop after the load, not to order
> storage versus storage.
I think the point is to make sure that the writing of the CCSR_DDR_SDRAM_CFG_2
does really take effect before we begin to delay loop. The sequence "write,
readback, sync" will guarantee this according to the manual. If we just want to
order the delay loop after the load, the following sequence should be enough:
store to CCSR_DDR_SDRAM_CFG_2
load from CCSR_DDR_SDRAM_CFG_2
isync or sync
delay loop
Why do we need the 'date dependency' here? According to the e6500 manual, the
instructions can execute out of order, but complete in order. So I am really
wondering why we need to order the load and the following delay loop if there
is no intention to order the storage access?
>
> This is a sequence we're already using on all of our I/O loads
> (excluding accesses like in this patch that don't use the standard
> accessors). I'm confident that it works even if it's not
> architecturally guaranteed.
This sequence is used to order the load and the followed storage access.
And this is guaranteed by the architecture. But I don't think it is suitable
for a case like this. The following is quoted from PowerISA:
Because stores cannot be performed “out-of-order”
(see Book III), if a Store instruction depends on the
value returned by a preceding Load instruction
(because the value returned by the Load is used to
compute either the effective address specified by the
Store or the value to be stored), the corresponding stor-
age accesses are performed in program order. The
same applies if whether the Store instruction is exe-
cuted depends on a conditional Branch instruction that
in turn depends on the value returned by a preceding
Load instruction.
Because an isync instruction prevents the execution of
instructions following the isync until instructions pre-
ceding the isync have completed, if an isync follows a
conditional Branch instruction that depends on the
value returned by a preceding Load instruction, the
load on which the Branch depends is performed before
any loads caused by instructions following the isync.
I think the above description would guarantee that the load will be performed
before any storage access (both load and store) following the isync in the
following scenario:
lwz r4, 0(r3)
twi 0, r4, 0
isync
> I'm not sure that there exists a clear
> architectural way of synchronizing non-storage instructions relative to
> storage instructions.
Isn't what the execution synchronization instructions such as sync, isync, mtmsr
do?
>
> Given that isync is documented as preventing any execution of
> instructions after the isync until all previous instructions complete,
> it doesn't seem to make sense for the architecture to explicitly talk
> about loads (as opposed to any other instruction) following a load,
> dependent conditional branch, isync sequence.
Sorry, I didn't get what you mean.
>
> > So if we want to order all the storage access as well
> > as execution synchronization, we should choose sync here.
>
> Do we need execution synchronization or context synchronization?
There is no context-altering instruction here, so I think an execution
synchronizing instruction should be enough here.
>
> The t4240 RM section that talks about a readback and a sync is in the
> context of subsequent memory operations ("Then accesses can safely be
> made to memory regions affected..."), not arbitrary instructions.
I assume that this sequence also guarantee that the writing does take effect.
> There
> are also a couple other places in the RM where isync is recommended
> instead (when setting LAWs or CCSRBAR), even though those also only
> involve memory accesses.
No idea why isync is used here.
>
> In any case, this is not performance critical and thus it's better to
> oversynchronize than undersynchronize.
On the contrary I think that sync is oversynchronize instead of
undersynchronize. It not only provide the execution synchronizing but also
order all the storage accesses. That is why I prefer the sync. :-)
Thanks,
Kevin
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-16 4:58 ` Kevin Hao
@ 2014-03-18 23:18 ` Scott Wood
2014-03-20 11:47 ` Kevin Hao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-18 23:18 UTC (permalink / raw)
To: Kevin Hao; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
On Sun, 2014-03-16 at 12:58 +0800, Kevin Hao wrote:
> On Fri, Mar 14, 2014 at 05:26:27PM -0500, Scott Wood wrote:
> > On Thu, 2014-03-13 at 15:46 +0800, Kevin Hao wrote:
> > > On Wed, Mar 12, 2014 at 12:43:05PM -0500, Scott Wood wrote:
> > > > > Shouldn't we use "readback, sync" here? The following is quoted form t4240RM:
> > > > > To guarantee that the results of any sequence of writes to configuration
> > > > > registers are in effect, the final configuration register write should be
> > > > > immediately followed by a read of the same register, and that should be
> > > > > followed by a SYNC instruction. Then accesses can safely be made to memory
> > > > > regions affected by the configuration register write.
> > > >
> > > > I agree that the sync before the readback is probably not necessary,
> > > > since transactions to the same address should already be ordered.
> > > >
> > > > A sync after the readback helps if you're trying to order the readback
> > > > with subsequent memory accesses, though in that case wouldn't a sync
> > > > alone (no readback) be adequate?
> > >
> > > No, we don't just want to order the subsequent memory access here.
> > > The 'write, readback, sync' is the required sequence if we want to make
> > > sure that the writing to CCSR register does really take effect.
> > >
> > > > Though maybe not always -- see the
> > > > comment near the end of fsl_elbc_write_buf() in
> > > > drivers/mtd/nand_fsl_elbc.c. I guess the readback does more than just
> > > > make sure the device has seen the write, ensuring that the device has
> > > > finished the transaction to the point of acting on another one.
> > >
> > > Agree.
> > >
> > > >
> > > > The data dependency plus isync sequence, which is done by the normal I/O
> > > > accessors used from C code, orders the readback versus all future
> > > > instructions (not just I/O). The delay loop is not I/O.
> > >
> > > According to the PowerISA, the sequence 'load, date dependency, isync' only
> > > order the load accesses.
> >
> > The point is to order the delay loop after the load, not to order
> > storage versus storage.
>
> I think the point is to make sure that the writing of the CCSR_DDR_SDRAM_CFG_2
> does really take effect before we begin to delay loop.
Yes.
> The sequence "write, readback, sync" will guarantee this according to the manual.
If you're referring to the section you quoted above, the manual does not
say that. It only talks about when accesses "to memory regions affected
by the configuration register write" can be safely made.
> If we just want to
> order the delay loop after the load, the following sequence should be enough:
> store to CCSR_DDR_SDRAM_CFG_2
> load from CCSR_DDR_SDRAM_CFG_2
> isync or sync
> delay loop
>
> Why do we need the 'date dependency' here? According to the e6500 manual, the
> instructions can execute out of order, but complete in order. So I am really
> wondering why we need to order the load and the following delay loop if there
> is no intention to order the storage access?
The data (not date) dependency means that the twi will not execute until
after the load instruction returns data (thus, after the device has
responded to the load). The twi, being a flow control instruction
rather than a storage instruction, should be fully ordered by isync.
>From the isync description in the ISA: "Except as described in the
preceding sentence, the isync instruction may complete before storage
accesses associated with instructions preceding the
isync instruction have been performed."
I don't know if that really applies to loads (as opposed to stores), and
it probably doesn't apply to guarded loads, but I feel safer leaving the
twi in.
As for sync instead of isync, I see nothing to indicate that it would be
adequate (though it may be that the only reason there needed to be a
delay loop in the first place was the lack of a readback/sync before
doing other I/O, in which case this is moot).
> > This is a sequence we're already using on all of our I/O loads
> > (excluding accesses like in this patch that don't use the standard
> > accessors). I'm confident that it works even if it's not
> > architecturally guaranteed.
>
> This sequence is used to order the load and the followed storage access.
It's also used to order loads versus other things, such as enabling
MSR[EE].
> And this is guaranteed by the architecture. But I don't think it is suitable
> for a case like this. The following is quoted from PowerISA:
> Because stores cannot be performed “out-of-order”
> (see Book III), if a Store instruction depends on the
> value returned by a preceding Load instruction
> (because the value returned by the Load is used to
> compute either the effective address specified by the
> Store or the value to be stored), the corresponding stor-
> age accesses are performed in program order. The
> same applies if whether the Store instruction is exe-
> cuted depends on a conditional Branch instruction that
> in turn depends on the value returned by a preceding
> Load instruction.
>
> Because an isync instruction prevents the execution of
> instructions following the isync until instructions pre-
> ceding the isync have completed, if an isync follows a
> conditional Branch instruction that depends on the
> value returned by a preceding Load instruction, the
> load on which the Branch depends is performed before
> any loads caused by instructions following the isync.
>
> I think the above description would guarantee that the load will be performed
> before any storage access (both load and store) following the isync in the
> following scenario:
> lwz r4, 0(r3)
> twi 0, r4, 0
> isync
I think it's a poorly worded section, but yes, it guarantees both loads
and stores -- unnecessarily doing so in separate places with different
wording. But by the definition of isync I don't see why it does not
apply to *any* instruction after the isync, not just loads and stores.
> > I'm not sure that there exists a clear
> > architectural way of synchronizing non-storage instructions relative to
> > storage instructions.
>
> Isn't what the execution synchronization instructions such as sync, isync, mtmsr
> do?
No. Execution synchronizing just says that the previous instructions
"have completed to a point at which they have reported all the
exceptions they will cause" (I'm assuming this doesn't include machine
check error reports), and that the previous instructions won't be
affected by context changes after the execution synchronizing
instruction, not that the previous instructions are fully completed.
> > Given that isync is documented as preventing any execution of
> > instructions after the isync until all previous instructions complete,
> > it doesn't seem to make sense for the architecture to explicitly talk
> > about loads (as opposed to any other instruction) following a load,
> > dependent conditional branch, isync sequence.
>
> Sorry, I didn't get what you mean.
I mean that I do not understand why it says, "the load on which the
Branch depends is performed before any loads caused by instructions
following the isync" rather than "the Load on which the Branch depends
is performed before any instructions following the isync".
> > > So if we want to order all the storage access as well
> > > as execution synchronization, we should choose sync here.
> >
> > Do we need execution synchronization or context synchronization?
>
> There is no context-altering instruction here, so I think an execution
> synchronizing instruction should be enough here.
Is the ISA ever explicit about what constitutes "context"? In any case,
just because we don't need that aspect of context synchronization
doesn't mean execution synchronization is enough. The behavior we want
is described in the isync instruction specifically, not in "context
synchronization" or "execution synchronization".
> > The t4240 RM section that talks about a readback and a sync is in the
> > context of subsequent memory operations ("Then accesses can safely be
> > made to memory regions affected..."), not arbitrary instructions.
>
> I assume that this sequence also guarantee that the writing does take effect.
You may assume that, but the manual doesn't say that. Sync could
(AFAIK) be implemented by emitting a barrier on the bus, or delaying
future storage accesses, rather than waiting for everything to have
finished before proceeding.
> > In any case, this is not performance critical and thus it's better to
> > oversynchronize than undersynchronize.
>
> On the contrary I think that sync is oversynchronize instead of
> undersynchronize. It not only provide the execution synchronizing but also
> order all the storage accesses. That is why I prefer the sync. :-)
sync is not a superset of isync. isync is not a superset of sync. If
you want to oversynchronize to be safe, do both (though even that isn't
equivalent to a barrier that orders everything, which is partly why a
readback is needed).
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-18 23:18 ` Scott Wood
@ 2014-03-20 11:47 ` Kevin Hao
2014-03-20 11:59 ` David Laight
2014-03-20 22:17 ` Scott Wood
0 siblings, 2 replies; 50+ messages in thread
From: Kevin Hao @ 2014-03-20 11:47 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 6168 bytes --]
On Tue, Mar 18, 2014 at 06:18:54PM -0500, Scott Wood wrote:
> > The sequence "write, readback, sync" will guarantee this according to the manual.
>
> If you're referring to the section you quoted above, the manual does not
> say that. It only talks about when accesses "to memory regions affected
> by the configuration register write" can be safely made.
To guarantee that the results of any sequence of writes to configuration
registers are in effect, the final configuration register write should be
immediately followed by a read of the same register, and that should be
followed by a SYNC instruction. Then accesses can safely be made to memory
regions affected by the configuration register write.
According to the above description in t4240 RM manual (2.6.1 Accessing CCSR
Memory from the Local Processor), that the writing to configuration register
takes effect is a prerequisite for the memory access to the affected regions.
>
> > If we just want to
> > order the delay loop after the load, the following sequence should be enough:
> > store to CCSR_DDR_SDRAM_CFG_2
> > load from CCSR_DDR_SDRAM_CFG_2
> > isync or sync
> > delay loop
> >
> > Why do we need the 'date dependency' here? According to the e6500 manual, the
> > instructions can execute out of order, but complete in order. So I am really
> > wondering why we need to order the load and the following delay loop if there
> > is no intention to order the storage access?
>
> The data (not date) dependency means that the twi will not execute until
> after the load instruction returns data (thus, after the device has
> responded to the load). The twi, being a flow control instruction
> rather than a storage instruction, should be fully ordered by isync.
>
> From the isync description in the ISA: "Except as described in the
> preceding sentence, the isync instruction may complete before storage
> accesses associated with instructions preceding the
> isync instruction have been performed."
>
> I don't know if that really applies to loads (as opposed to stores), and
> it probably doesn't apply to guarded loads, but I feel safer leaving the
> twi in.
>
> As for sync instead of isync, I see nothing to indicate that it would be
> adequate (though it may be that the only reason there needed to be a
> delay loop in the first place was the lack of a readback/sync before
> doing other I/O, in which case this is moot).
OK, so the intention of 'twi, isync' following the load is not to order the
following storage access, but order the following delay loop instructions,
right? But according to the e6500 manual, the instructions complete in order.
The following is the definition of 'complete':
Complete—An instruction is eligible to complete after it finishes executing
and makes its results available for subsequent instructions. Instructions
must complete in order from the bottom two entries of the
completion queue (CQ). The completion unit coordinates how instructions (which
may have executed out of order) affect architected registers to ensure the
appearance of serial execution. This guarantees that the completed instruction
and all previous instructions can cause no exceptions. An instruction completes
when it is retired, that is, deleted from the CQ.
So the following delay loop instructions should never complete before the
complete of the load instruction. After the complete of load instruction,
the data should already been updated to the architecture register. So we can
guarantee that the load instruction get the data (the device has responded to
the load) before the complete of the following delay loop instructions, why do
we need the additional 'twi, isync'? Then for a case like this (which don't
need order the following storage access), I think the following sequence should
be enough:
write to configuration register
read back
delay loop
> I mean that I do not understand why it says, "the load on which the
> Branch depends is performed before any loads caused by instructions
> following the isync" rather than "the Load on which the Branch depends
> is performed before any instructions following the isync".
When we talk about the 'performed' here, we should only mean the effect of
storage access. The following is the definition of 'performed':
performed
A load or instruction fetch by a processor or mech-
anism (P1) is performed with respect to any pro-
cessor or mechanism (P2) when the value to be
returned by the load or instruction fetch can no
longer be changed by a store by P2. A store by P1
is performed with respect to P2 when a load by P2
from the location accessed by the store will return
the value stored (or a value stored subsequently).
An instruction cache block invalidation by P1 is
performed with respect to P2 when an instruction
fetch by P2 will not be satisfied from the copy of
the block that existed in its instruction cache when
the instruction causing the invalidation was exe-
cuted, and similarly for a data cache block invalida-
tion.
The preceding definitions apply regardless of
whether P1 and P2 are the same entity.
>
> > > > So if we want to order all the storage access as well
> > > > as execution synchronization, we should choose sync here.
> > >
> > > Do we need execution synchronization or context synchronization?
> >
> > There is no context-altering instruction here, so I think an execution
> > synchronizing instruction should be enough here.
>
> Is the ISA ever explicit about what constitutes "context"?
The following is the definition of context-altering instruction:
An instruction that alters the context in which data
addresses or instruction addresses are interpreted, or
in which instructions are executed or data accesses are
performed, is called a context-altering instruction.
So the context should be:
- in which data addresses or instruction addresses are interpreted
- in which instructions are executed
- in which data accesses are performed
Thanks,
Kevin
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply [flat|nested] 50+ messages in thread
* RE: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-20 11:47 ` Kevin Hao
@ 2014-03-20 11:59 ` David Laight
2014-03-20 22:07 ` Scott Wood
2014-03-20 22:17 ` Scott Wood
1 sibling, 1 reply; 50+ messages in thread
From: David Laight @ 2014-03-20 11:59 UTC (permalink / raw)
To: 'Kevin Hao', Scott Wood
Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
RnJvbTogS2V2aW4gSGFvDQo+IFNlbnQ6IDIwIE1hcmNoIDIwMTQgMTE6NDgNCj4gVG86IFNjb3R0
IFdvb2QNCj4gQ2M6IGxpbnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3JnOyBDaGVuaHVpIFpoYW87
IEphc29uLkppbkBmcmVlc2NhbGUuY29tOyBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnDQo+
IFN1YmplY3Q6IFJlOiBbUEFUQ0ggOS85XSBwb3dlcnBjL3BtOiBzdXBwb3J0IGRlZXAgc2xlZXAg
ZmVhdHVyZSBvbiBUMTA0MA0KPiANCj4gT24gVHVlLCBNYXIgMTgsIDIwMTQgYXQgMDY6MTg6NTRQ
TSAtMDUwMCwgU2NvdHQgV29vZCB3cm90ZToNCj4gPiA+ICBUaGUgc2VxdWVuY2UgIndyaXRlLCBy
ZWFkYmFjaywgc3luYyIgd2lsbCBndWFyYW50ZWUgdGhpcyBhY2NvcmRpbmcgdG8gdGhlIG1hbnVh
bC4NCj4gPg0KPiA+IElmIHlvdSdyZSByZWZlcnJpbmcgdG8gdGhlIHNlY3Rpb24geW91IHF1b3Rl
ZCBhYm92ZSwgdGhlIG1hbnVhbCBkb2VzIG5vdA0KPiA+IHNheSB0aGF0LiAgSXQgb25seSB0YWxr
cyBhYm91dCB3aGVuIGFjY2Vzc2VzICJ0byBtZW1vcnkgcmVnaW9ucyBhZmZlY3RlZA0KPiA+IGJ5
IHRoZSBjb25maWd1cmF0aW9uIHJlZ2lzdGVyIHdyaXRlIiBjYW4gYmUgc2FmZWx5IG1hZGUuDQo+
IA0KPiAgIFRvIGd1YXJhbnRlZSB0aGF0IHRoZSByZXN1bHRzIG9mIGFueSBzZXF1ZW5jZSBvZiB3
cml0ZXMgdG8gY29uZmlndXJhdGlvbg0KPiAgIHJlZ2lzdGVycyBhcmUgaW4gZWZmZWN0LCB0aGUg
ZmluYWwgY29uZmlndXJhdGlvbiByZWdpc3RlciB3cml0ZSBzaG91bGQgYmUNCj4gICBpbW1lZGlh
dGVseSBmb2xsb3dlZCBieSBhIHJlYWQgb2YgdGhlIHNhbWUgcmVnaXN0ZXIsIGFuZCB0aGF0IHNo
b3VsZCBiZQ0KPiAgIGZvbGxvd2VkIGJ5IGEgU1lOQyBpbnN0cnVjdGlvbi4gVGhlbiBhY2Nlc3Nl
cyBjYW4gc2FmZWx5IGJlIG1hZGUgdG8gbWVtb3J5DQo+ICAgcmVnaW9ucyBhZmZlY3RlZCBieSB0
aGUgY29uZmlndXJhdGlvbiByZWdpc3RlciB3cml0ZS4NCg0KVGhhdCBzb3J0IG9mIHNlcXVlbmNl
IGlzIG5lZWQgdG8gZm9yY2UgdGhlIG9wZXJhdGlvbnMgdGhyb3VnaCBhbnkNCmV4dGVybmFsIGJ1
cyAtIGFmdGVyIHRoZSBjcHUgaXRzZWxmIGhhcyBpc3N1ZWQgdGhlIGJ1cyBjeWNsZXMuDQpNb3N0
bHkgcmVxdWlyZWQgYmVjYXVzZSB3cml0ZXMgYXJlIG9mdGVuICdwb3N0ZWQnIChpZSBhZGRyZXNz
IGFuZCBkYXRhDQpsYXRjaGVkLCBhbmQgdGhlbiBwZXJmb3JtZWQgc3luY2hyb25vdXNseSkuDQoN
Cj4gQWNjb3JkaW5nIHRvIHRoZSBhYm92ZSBkZXNjcmlwdGlvbiBpbiB0NDI0MCBSTSBtYW51YWwg
KDIuNi4xIEFjY2Vzc2luZyBDQ1NSDQo+IE1lbW9yeSBmcm9tIHRoZSBMb2NhbCBQcm9jZXNzb3Ip
LCB0aGF0IHRoZSB3cml0aW5nIHRvIGNvbmZpZ3VyYXRpb24gcmVnaXN0ZXINCj4gdGFrZXMgZWZm
ZWN0IGlzIGEgcHJlcmVxdWlzaXRlIGZvciB0aGUgbWVtb3J5IGFjY2VzcyB0byB0aGUgYWZmZWN0
ZWQgcmVnaW9ucy4NCi4uLg0KPiBPSywgc28gdGhlIGludGVudGlvbiBvZiAndHdpLCBpc3luYycg
Zm9sbG93aW5nIHRoZSBsb2FkIGlzIG5vdCB0byBvcmRlciB0aGUNCj4gZm9sbG93aW5nIHN0b3Jh
Z2UgYWNjZXNzLCBidXQgb3JkZXIgdGhlIGZvbGxvd2luZyBkZWxheSBsb29wIGluc3RydWN0aW9u
cywNCj4gcmlnaHQNCg0KSSB0cmllZCB0byB3b3JrIG91dCB3aGF0IHRoZSAndHdpLCBpc3luYycg
aW5zdHJ1Y3Rpb25zIHdlcmUgZm9yIChpbiBpbl9sZTMyKCkpLg0KVGhlIGJlc3QgSSBjb3VsZCBj
b21lIHVwIHdpdGggd2FzIHRvIGVuc3VyZSBhIHN5bmNocm9ub3VzIGJ1cy1mYXVsdC4NCkJ1dCBi
dXMgZmF1bHRzIGFyZSBwcm9iYWJseSBvbmx5IGV4cGVjdGVkIGR1cmluZyBkZXZpY2UgcHJvYmlu
ZyAtIG5vdA0Kbm9ybWFsIG9wZXJhdGlvbiwgYW5kIHRoZSBpbnN0cnVjdGlvbnMgd2lsbCBoYXZl
IGEgc2lnbmlmaWNhbnQgY29zdC4NCg0KQWRkaXRpb25hbGx5IGluX2xlMzIoKSBhbmQgb3V0X2xl
MzIoKSBib3RoIHN0YXJ0IHdpdGggYSAnc3luYycgaW5zdHJ1Y3Rpb24uDQpJbiBtYW55IGNhc2Vz
IHRoYXQgaXNuJ3QgbmVlZGVkIGVpdGhlciAtIGFuIGV4cGxpY2l0IGlvc3luYygpIGNhbiBiZQ0K
dXNlZCBhZnRlciBncm91cHMgb2YgaW5zdHJ1Y3Rpb25zLg0KDQoJRGF2aWQNCg0KDQo=
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-20 11:59 ` David Laight
@ 2014-03-20 22:07 ` Scott Wood
2014-03-21 9:21 ` David Laight
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-20 22:07 UTC (permalink / raw)
To: David Laight
Cc: linuxppc-dev, 'Kevin Hao', Chenhui Zhao, Jason.Jin, linux-kernel
On Thu, 2014-03-20 at 11:59 +0000, David Laight wrote:
> I tried to work out what the 'twi, isync' instructions were for (in in_le32()).
> The best I could come up with was to ensure a synchronous bus-fault.
> But bus faults are probably only expected during device probing - not
> normal operation, and the instructions will have a significant cost.
>
> Additionally in_le32() and out_le32() both start with a 'sync' instruction.
> In many cases that isn't needed either - an explicit iosync() can be
> used after groups of instructions.
The idea is that it's better to be maximally safe by default, and let
performance critical sections be optimized using raw accessors and
explicit synchronization if needed, than to have hard-to-debug bugs due
to missing/wrong sync. A lot of I/O is slow enough that the performance
impact doesn't really matter, but the brain-time cost of getting the
sync right is still there.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* RE: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-20 22:07 ` Scott Wood
@ 2014-03-21 9:21 ` David Laight
2014-03-21 21:16 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: David Laight @ 2014-03-21 9:21 UTC (permalink / raw)
To: 'Scott Wood'
Cc: linuxppc-dev, 'Kevin Hao', Chenhui Zhao, Jason.Jin, linux-kernel
RnJvbTogU2NvdHQgV29vZCBbbWFpbHRvOnNjb3R0d29vZEBmcmVlc2NhbGUuY29tXQ0KPiBPbiBU
aHUsIDIwMTQtMDMtMjAgYXQgMTE6NTkgKzAwMDAsIERhdmlkIExhaWdodCB3cm90ZToNCj4gPiBJ
IHRyaWVkIHRvIHdvcmsgb3V0IHdoYXQgdGhlICd0d2ksIGlzeW5jJyBpbnN0cnVjdGlvbnMgd2Vy
ZSBmb3IgKGluIGluX2xlMzIoKSkuDQo+ID4gVGhlIGJlc3QgSSBjb3VsZCBjb21lIHVwIHdpdGgg
d2FzIHRvIGVuc3VyZSBhIHN5bmNocm9ub3VzIGJ1cy1mYXVsdC4NCj4gPiBCdXQgYnVzIGZhdWx0
cyBhcmUgcHJvYmFibHkgb25seSBleHBlY3RlZCBkdXJpbmcgZGV2aWNlIHByb2JpbmcgLSBub3QN
Cj4gPiBub3JtYWwgb3BlcmF0aW9uLCBhbmQgdGhlIGluc3RydWN0aW9ucyB3aWxsIGhhdmUgYSBz
aWduaWZpY2FudCBjb3N0Lg0KPiA+DQo+ID4gQWRkaXRpb25hbGx5IGluX2xlMzIoKSBhbmQgb3V0
X2xlMzIoKSBib3RoIHN0YXJ0IHdpdGggYSAnc3luYycgaW5zdHJ1Y3Rpb24uDQo+ID4gSW4gbWFu
eSBjYXNlcyB0aGF0IGlzbid0IG5lZWRlZCBlaXRoZXIgLSBhbiBleHBsaWNpdCBpb3N5bmMoKSBj
YW4gYmUNCj4gPiB1c2VkIGFmdGVyIGdyb3VwcyBvZiBpbnN0cnVjdGlvbnMuDQo+IA0KPiBUaGUg
aWRlYSBpcyB0aGF0IGl0J3MgYmV0dGVyIHRvIGJlIG1heGltYWxseSBzYWZlIGJ5IGRlZmF1bHQs
IGFuZCBsZXQNCj4gcGVyZm9ybWFuY2UgY3JpdGljYWwgc2VjdGlvbnMgYmUgb3B0aW1pemVkIHVz
aW5nIHJhdyBhY2Nlc3NvcnMgYW5kDQo+IGV4cGxpY2l0IHN5bmNocm9uaXphdGlvbiBpZiBuZWVk
ZWQsIHRoYW4gdG8gaGF2ZSBoYXJkLXRvLWRlYnVnIGJ1Z3MgZHVlDQo+IHRvIG1pc3Npbmcvd3Jv
bmcgc3luYy4gIEEgbG90IG9mIEkvTyBpcyBzbG93IGVub3VnaCB0aGF0IHRoZSBwZXJmb3JtYW5j
ZQ0KPiBpbXBhY3QgZG9lc24ndCByZWFsbHkgbWF0dGVyLCBidXQgdGhlIGJyYWluLXRpbWUgY29z
dCBvZiBnZXR0aW5nIHRoZQ0KPiBzeW5jIHJpZ2h0IGlzIHN0aWxsIHRoZXJlLg0KDQpIbW1tLi4u
Lg0KDQpUaGF0IG1pZ2h0IGJlIGFuIGV4Y3VzZSBmb3IgdGhlICdzeW5jJywgYnV0IG5vdCB0aGUg
dHdpIGFuZCBpc3luYy4NCg0KSSB3YXMgc2V0dGluZyB1cCBhIGRtYSByZXF1ZXN0IChmb3IgdGhl
IHBwYyA4M3h4IFBDSWUgYnJpZGdlKSBhbmQNCndhcyBkb2luZyBiYWNrIHRvIGJhY2sgbGl0dGxl
LWVuZGlhbiB3cml0ZXMgaW50byBtZW1vcnkuDQpJIGhhZCBkaWZmaWN1bHR5IGZpbmRpbmcgYW5k
IGluY2x1ZGluZyBoZWFkZXIgZmlsZXMgY29udGFpbmluZw0KdGhlIGRlZmluaXRpb25zIGZvciBi
eXRlc3dhcHBlZCBhY2Nlc3NlcyBJIG5lZWRlZC4NCmFyY2gvcG93ZXJwYy9pbmNsdWRlL2FzbS9z
d2FiLmggY29udGFpbnMgc29tZSAtIGJ1dCBJIGNvdWxkbid0DQp3b3JrIG91dCBob3cgdG8gZ2V0
IGl0IGluY2x1ZGVkIChhcGFydCBmcm9tIGdpdmluZyB0aGUgZnVsbCBwYXRoKS4NCg0KSW4gYW55
IGNhc2UgeW91IG5lZWQgdG8gdW5kZXJzdGFuZCB3aGVuIHN5bmNocm9uaXNhdGlvbiBpcw0KcmVx
dWlyZWQgLSBvdGhlcndpc2UgeW91IHdpbGwgZ2V0IGl0IHdyb25nLg0KRXNwZWNpYWxseSBzaW5j
ZSBub24tYnl0ZXN3YXBwZWQgYWNjZXNzZXMgYXJlIGRvbmUgYnkgZGlyZWN0DQphY2Nlc3MuDQoN
CglEYXZpZA0KDQo=
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-21 9:21 ` David Laight
@ 2014-03-21 21:16 ` Scott Wood
0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2014-03-21 21:16 UTC (permalink / raw)
To: David Laight
Cc: linuxppc-dev, 'Kevin Hao', Chenhui Zhao, Jason.Jin, linux-kernel
On Fri, 2014-03-21 at 09:21 +0000, David Laight wrote:
> From: Scott Wood [mailto:scottwood@freescale.com]
> > On Thu, 2014-03-20 at 11:59 +0000, David Laight wrote:
> > > I tried to work out what the 'twi, isync' instructions were for (in in_le32()).
> > > The best I could come up with was to ensure a synchronous bus-fault.
> > > But bus faults are probably only expected during device probing - not
> > > normal operation, and the instructions will have a significant cost.
> > >
> > > Additionally in_le32() and out_le32() both start with a 'sync' instruction.
> > > In many cases that isn't needed either - an explicit iosync() can be
> > > used after groups of instructions.
> >
> > The idea is that it's better to be maximally safe by default, and let
> > performance critical sections be optimized using raw accessors and
> > explicit synchronization if needed, than to have hard-to-debug bugs due
> > to missing/wrong sync. A lot of I/O is slow enough that the performance
> > impact doesn't really matter, but the brain-time cost of getting the
> > sync right is still there.
>
> Hmmm....
>
> That might be an excuse for the 'sync', but not the twi and isync.
That might be true if I/O is always cache inhibited and guarded, in
which case I think we can rely on that to ensure that the load has
completed before we do things like wrtee or rfi. In any case, I'd want
to hear Ben's explanation.
> I was setting up a dma request (for the ppc 83xx PCIe bridge) and
> was doing back to back little-endian writes into memory.
> I had difficulty finding and including header files containing
> the definitions for byteswapped accesses I needed.
> arch/powerpc/include/asm/swab.h contains some - but I couldn't
> work out how to get it included (apart from giving the full path).
>
> In any case you need to understand when synchronisation is
> required - otherwise you will get it wrong.
> Especially since non-byteswapped accesses are done by direct
> access.
Yes, it's bad that rawness combines the lack of byteswapping with the
lack of synchronization. Ideally the raw accessors would also come in
big and little endian form, plus a native endian form if it's really
needed.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-20 11:47 ` Kevin Hao
2014-03-20 11:59 ` David Laight
@ 2014-03-20 22:17 ` Scott Wood
1 sibling, 0 replies; 50+ messages in thread
From: Scott Wood @ 2014-03-20 22:17 UTC (permalink / raw)
To: Kevin Hao; +Cc: linuxppc-dev, Chenhui Zhao, Jason.Jin, linux-kernel
On Thu, 2014-03-20 at 19:47 +0800, Kevin Hao wrote:
> OK, so the intention of 'twi, isync' following the load is not to order the
> following storage access, but order the following delay loop instructions,
> right? But according to the e6500 manual, the instructions complete in order.
> The following is the definition of 'complete':
> Complete—An instruction is eligible to complete after it finishes executing
> and makes its results available for subsequent instructions. Instructions
> must complete in order from the bottom two entries of the
> completion queue (CQ). The completion unit coordinates how instructions (which
> may have executed out of order) affect architected registers to ensure the
> appearance of serial execution. This guarantees that the completed instruction
> and all previous instructions can cause no exceptions. An instruction completes
> when it is retired, that is, deleted from the CQ.
>
> So the following delay loop instructions should never complete before the
> complete of the load instruction.
We don't want the delay loop instructions to *start* until the load has
completed. Completion of the loop only matters when ordering the loop
versus post-loop actions (and again, there we'd want the loop to
complete before subsequent actions start).
> > > > > So if we want to order all the storage access as well
> > > > > as execution synchronization, we should choose sync here.
> > > >
> > > > Do we need execution synchronization or context synchronization?
> > >
> > > There is no context-altering instruction here, so I think an execution
> > > synchronizing instruction should be enough here.
> >
> > Is the ISA ever explicit about what constitutes "context"?
>
> The following is the definition of context-altering instruction:
> An instruction that alters the context in which data
> addresses or instruction addresses are interpreted, or
> in which instructions are executed or data accesses are
> performed, is called a context-altering instruction.
>
> So the context should be:
> - in which data addresses or instruction addresses are interpreted
> - in which instructions are executed
> - in which data accesses are performed
By that definition, a store to CCSR could easily change the context in
which data accesses are performed, by changing a mapping.
But still, nothing in the above defines "context" -- or rather, it does
so circularly. While it makes intuitive sense that it would be limited
to context that lives within the core, rather than the rest of the
system, I don't think the ISA generally distinguishes between the two.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-12 1:10 ` Scott Wood
2014-03-12 5:57 ` Kevin Hao
@ 2014-03-12 10:40 ` Chenhui Zhao
2014-03-14 23:18 ` Scott Wood
1 sibling, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-12 10:40 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > From: Zhao Chenhui <chenhui.zhao@freescale.com>
> >
> > T1040 supports 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 will be prefetched.
> >
> > Due to the different initialization code between 32-bit and 64-bit, they
> > have seperate resume entry and precedure.
> >
> > The feature supports 32-bit and 64-bit kernel mode.
> >
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > ---
> > arch/powerpc/include/asm/booke_save_regs.h | 3 +
> > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
> > arch/powerpc/kernel/head_fsl_booke.S | 30 +++
> > arch/powerpc/platforms/85xx/Makefile | 2 +-
> > arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
> > arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
> > arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
> > arch/powerpc/sysdev/fsl_soc.h | 7 +
> > 8 files changed, 592 insertions(+), 1 deletions(-)
> > create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> > create mode 100644 arch/powerpc/platforms/85xx/sleep.S
> >
> > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > index 87c357a..37c1f6c 100644
> > --- a/arch/powerpc/include/asm/booke_save_regs.h
> > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > @@ -88,6 +88,9 @@
> > #define HIBERNATION_FLAG 1
> > #define DEEPSLEEP_FLAG 2
> >
> > +#define CPLD_FLAG 1
> > +#define FPGA_FLAG 2
>
> What is this?
We have two kind of boards, QDS and RDB. They have different register
map. Use the flag to indicate the current board is using which kind
of register map.
>
> > #ifndef __ASSEMBLY__
> > extern void booke_cpu_state_save(void *buf, int type);
> > extern void *booke_cpu_state_restore(void *buf, int type);
> > diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> > index e59d6de..ea9bc28 100644
> > --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> > +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> > @@ -318,6 +318,23 @@ flush_backside_L2_cache:
> > 2:
> > blr
> >
> > +#define CPC_CPCCSR0 0x0
> > +#define CPC_CPCCSR0_CPCFL 0x800
>
> This is supposed to be CPU setup, not platform setup.
>
> > +/* r3 : the base address of CPC */
> > +_GLOBAL(fsl_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
> > +
> > _GLOBAL(__flush_caches_e500v2)
>
> I'm not sure that this belongs here either.
Will find a better place.
>
> > mflr r0
> > bl flush_dcache_L1
> > diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> > index 20204fe..3285752 100644
> > --- a/arch/powerpc/kernel/head_fsl_booke.S
> > +++ b/arch/powerpc/kernel/head_fsl_booke.S
> > @@ -162,6 +162,19 @@ _ENTRY(__early_start)
> > #include "fsl_booke_entry_mapping.S"
> > #undef ENTRY_MAPPING_BOOT_SETUP
> >
> > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > + /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
> > + LOAD_REG_ADDR(r4, deep_sleep_flag)
> > + lwz r3, 0(r4)
> > + cmpwi r3, 0
> > + beq 11f
> > + /* clear deep_sleep_flag */
> > + li r3, 0
> > + stw r3, 0(r4)
> > + b fsl_deepsleep_resume
> > +11:
> > +#endif
>
> Why do you come in via the normal kernel entry, versus specifying a
> direct entry point for deep sleep resume? How does U-Boot even know
> what the normal entry is when resuming?
I wish to return to a specified point (like 64-bit mode), but the code in
fsl_booke_entry_mapping.S only can run in the first page. Because it
only setups a temp mapping of 4KB.
>
> Be careful of the "beq set_ivor" in the CONFIG_RELOCATABLE section
> above. Also you probably don't want the relocation code to run again
> when resuming.
When resuming, will run from the point __early_start. Don't run the code
in the CONFIG_RELOCATABLE section.
>
> > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > +_ENTRY(__entry_deep_sleep)
> > +/*
> > + * Bootloader will jump to here when resuming from deep sleep.
> > + * After executing the init code in fsl_booke_entry_mapping.S,
> > + * will jump to the real resume entry.
> > + */
> > + li r8, 1
> > + bl 12f
> > +12: mflr r9
> > + addi r9, r9, (deep_sleep_flag - 12b)
> > + stw r8, 0(r9)
> > + b __early_start
> > +deep_sleep_flag:
> > + .long 0
> > +#endif
>
> It's a bit ambiguous to say "entry_deep_sleep" when it's resuming rather
> than entering...
How about __fsl_entry_resume?
>
> So you do have a special entry point. Why do you go to __early_start
> only to quickly test a flag and branch away?
>
> > diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> > index 7fae817..9a4ea86 100644
> > --- a/arch/powerpc/platforms/85xx/Makefile
> > +++ b/arch/powerpc/platforms/85xx/Makefile
> > @@ -3,7 +3,7 @@
> > #
> > obj-$(CONFIG_SMP) += smp.o
> > ifeq ($(CONFIG_FSL_CORENET_RCPM), y)
> > -obj-$(CONFIG_SUSPEND) += qoriq_pm.o
> > +obj-$(CONFIG_SUSPEND) += qoriq_pm.o deepsleep.o sleep.o
> > endif
> >
> > 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..ddd7185
> > --- /dev/null
> > +++ b/arch/powerpc/platforms/85xx/deepsleep.c
> > @@ -0,0 +1,201 @@
> > +/*
> > + * Support deep sleep feature
>
> AFAICT this supports deep sleep on T1040, not on all 85xx that has it.
Yes, for now T1040 and T1042.
>
> > + *
> > + * Copyright 2014 Freescale Semiconductor Inc.
> > + *
> > + * Author: Chenhui Zhao <chenhui.zhao@freescale.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/of_platform.h>
> > +#include <linux/of_address.h>
> > +#include <asm/machdep.h>
> > +#include <sysdev/fsl_soc.h>
> > +#include <asm/booke_save_regs.h>
> > +
> > +#define SIZE_1MB 0x100000
> > +#define SIZE_2MB 0x200000
> > +
> > +#define CCSR_SCFG_DPSLPCR 0xfc000
> > +#define CCSR_SCFG_DPSLPCR_WDRR_EN 0x1
> > +#define CCSR_SCFG_SPARECR2 0xfc504
> > +#define CCSR_SCFG_SPARECR3 0xfc508
> > +
> > +#define CCSR_GPIO1_GPDIR 0x130000
> > +#define CCSR_GPIO1_GPODR 0x130004
> > +#define CCSR_GPIO1_GPDAT 0x130008
> > +#define CCSR_GPIO1_GPDIR_29 0x4
> > +
> > +/* 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 void *dcsr_base, *ccsr_base, *pld_base;
> > +static int pld_flag;
> > +
> > +int fsl_dp_iomap(void)
> > +{
> > + struct device_node *np;
> > + const u32 *prop;
> > + int ret = 0;
> > + u64 ccsr_phy_addr, dcsr_phy_addr;
> > +
> > + np = of_find_node_by_type(NULL, "soc");
> > + if (!np) {
> > + pr_err("%s: Can't find the node of \"soc\"\n", __func__);
> > + ret = -EINVAL;
> > + goto ccsr_err;
> > + }
> > + prop = of_get_property(np, "ranges", NULL);
> > + if (!prop) {
> > + pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
> > + of_node_put(np);
> > + ret = -EINVAL;
> > + goto ccsr_err;
> > + }
>
> Use get_immrbase(), or better use specific nodes in the device tree.
>
> > + ccsr_phy_addr = of_translate_address(np, prop + 1);
> > + ccsr_base = ioremap((phys_addr_t)ccsr_phy_addr, SIZE_2MB);
> > + of_node_put(np);
> > + if (!ccsr_base) {
> > + ret = -ENOMEM;
> > + goto ccsr_err;
> > + }
>
> Unnecessary cast.
>
> Why 2 MiB?
All registers used are inside the 2MB address space.
>
> > + np = of_find_compatible_node(NULL, NULL, "fsl,dcsr");
> > + if (!np) {
> > + pr_err("%s: Can't find the node of \"fsl,dcsr\"\n", __func__);
> > + ret = -EINVAL;
> > + goto dcsr_err;
> > + }
> > + prop = of_get_property(np, "ranges", NULL);
> > + if (!prop) {
> > + pr_err("%s: Can't find the property of \"ranges\"\n", __func__);
> > + of_node_put(np);
> > + ret = -EINVAL;
> > + goto dcsr_err;
> > + }
> > + dcsr_phy_addr = of_translate_address(np, prop + 1);
> > + dcsr_base = ioremap((phys_addr_t)dcsr_phy_addr, SIZE_1MB);
> > + of_node_put(np);
> > + if (!dcsr_base) {
> > + ret = -ENOMEM;
> > + goto dcsr_err;
> > + }
>
> If you must do this, add a helper to get the dcsr base -- but do we not
> already have dcsr subnodes for what you are using?
>
> > +
> > + np = of_find_compatible_node(NULL, NULL, "fsl,fpga-qixis");
> > + if (np) {
> > + pld_flag = FPGA_FLAG;
> > + } else {
> > + np = of_find_compatible_node(NULL, NULL, "fsl,p104xrdb-cpld");
> > + if (np) {
> > + pld_flag = CPLD_FLAG;
> > + } else {
> > + pr_err("%s: Can't find the FPGA/CPLD node\n",
> > + __func__);
> > + ret = -EINVAL;
> > + goto pld_err;
> > + }
> > + }
>
> OK, so this file isn't even specific to T1040 -- it's specific to our
> reference boards?
Yes. There are some FPGA/CPLD setting which needed by deep sleep.
>
> > +static void fsl_dp_ddr_save(void *ccsr_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);
>
> That assumption may break with a relocatable kernel.
>
> > +
> > +}
> > +
> > +int fsl_enter_epu_deepsleep(void)
> > +{
> > +
> > +
>
> No blank lines at begin/end of function.
>
> > diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c
> > index 915b13b..5f2c016 100644
> > --- a/arch/powerpc/platforms/85xx/qoriq_pm.c
> > +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c
> > @@ -20,6 +20,8 @@
> > #define FSL_SLEEP 0x1
> > #define FSL_DEEP_SLEEP 0x2
> >
> > +int (*fsl_enter_deepsleep)(void);
> > +
> > /* specify the sleep state of the present platform */
> > int sleep_pm_state;
> > /* supported sleep modes by the present platform */
> > @@ -28,6 +30,7 @@ static unsigned int sleep_modes;
> > static int qoriq_suspend_enter(suspend_state_t state)
> > {
> > int ret = 0;
> > + int cpu;
> >
> > switch (state) {
> > case PM_SUSPEND_STANDBY:
> > @@ -39,6 +42,17 @@ static int qoriq_suspend_enter(suspend_state_t state)
> >
> > break;
> >
> > + case PM_SUSPEND_MEM:
> > +
> > + cpu = smp_processor_id();
> > + qoriq_pm_ops->irq_mask(cpu);
> > +
> > + ret = fsl_enter_deepsleep();
> > +
> > + qoriq_pm_ops->irq_unmask(cpu);
> > +
> > + break;
> > +
> > default:
> > ret = -EINVAL;
> >
> > @@ -52,12 +66,30 @@ static int qoriq_suspend_valid(suspend_state_t state)
> > if (state == PM_SUSPEND_STANDBY && (sleep_modes & FSL_SLEEP))
> > return 1;
> >
> > + if (state == PM_SUSPEND_MEM && (sleep_modes & FSL_DEEP_SLEEP))
> > + return 1;
> > +
> > return 0;
> > }
> >
> > +static int qoriq_suspend_begin(suspend_state_t state)
> > +{
> > + if (state == PM_SUSPEND_MEM)
> > + return fsl_dp_iomap();
> > +
> > + return 0;
> > +}
> > +
> > +static void qoriq_suspend_end(void)
> > +{
> > + fsl_dp_iounmap();
> > +}
> > +
> > static const struct platform_suspend_ops qoriq_suspend_ops = {
> > .valid = qoriq_suspend_valid,
> > .enter = qoriq_suspend_enter,
> > + .begin = qoriq_suspend_begin,
> > + .end = qoriq_suspend_end,
> > };
> >
> > static int __init qoriq_suspend_init(void)
> > @@ -71,6 +103,12 @@ static int __init qoriq_suspend_init(void)
> > if (np)
> > sleep_pm_state = PLAT_PM_LPM20;
> >
> > + np = of_find_compatible_node(NULL, NULL, "fsl,t1040-rcpm");
> > + if (np) {
> > + fsl_enter_deepsleep = fsl_enter_epu_deepsleep;
> > + sleep_modes |= FSL_DEEP_SLEEP;
> > + }
> > +
> > suspend_set_ops(&qoriq_suspend_ops);
> >
> > return 0;
> > diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
> > new file mode 100644
> > index 0000000..95a5746
> > --- /dev/null
> > +++ b/arch/powerpc/platforms/85xx/sleep.S
> > @@ -0,0 +1,295 @@
> > +/*
> > + * Implement the low level part of deep sleep
> > + *
> > + * Copyright 2014 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/booke_save_regs.h>
> > +#include <asm/mmu.h>
> > +
> > +#define FSLDELAY(count) \
> > + li r3, (count)@l; \
> > + slwi r3, r3, 10; \
> > + mtctr r3; \
> > +101: nop; \
> > + bdnz 101b;
>
> You don't need a namespace prefix on local macros in a non-header file.
>
> Is the timebase stopped where you're calling this from?
No. My purpose is to avoid jump in the last stage of entering deep sleep.
Jump may cause problem at that time.
>
> > +#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
> > +booke_regs_buffer:
> > + .space REGS_BUFFER_SIZE
> > +
> > + .section .txt
> > + .align 6
> > +
> > +_GLOBAL(fsl_dp_enter_low)
> > +deepsleep_start:
> > + LOAD_REG_ADDR(r9, buf_tmp)
> > + PPC_STL r3, 0(r9)
> > + PPC_STL r4, 8(r9)
> > + PPC_STL r5, 16(r9)
> > + PPC_STL r6, 24(r9)
> > +
> > + LOAD_REG_ADDR(r3, booke_regs_buffer)
> > + /* save the return address */
> > + mflr r5
> > + PPC_STL r5, SR_LR(r3)
> > + mfmsr r5
> > + PPC_STL r5, SR_MSR(r3)
> > + li r4, DEEPSLEEP_FLAG
> > + bl booke_cpu_state_save
> > +
> > + LOAD_REG_ADDR(r9, buf_tmp)
> > + PPC_LL r31, 0(r9)
> > + PPC_LL r30, 8(r9)
> > + PPC_LL r29, 16(r9)
> > + PPC_LL r28, 24(r9)
> > +
> > + /* flush caches */
> > + LOAD_REG_ADDR(r3, cur_cpu_spec)
> > + PPC_LL r3, 0(r3)
> > + PPC_LL r3, CPU_FLUSH_CACHES(r3)
> > + PPC_LCMPI 0, r3, 0
> > + beq 6f
> > +#ifdef CONFIG_PPC64
> > + PPC_LL r3, 0(r3)
> > +#endif
> > + mtctr r3
> > + bctrl
> > +6:
> > +#define CPC_OFFSET 0x10000
> > + mr r3, r31
> > + addis r3, r3, CPC_OFFSET@h
> > + bl fsl_flush_cpc_cache
> > +
> > + LOAD_REG_ADDR(r8, deepsleep_start)
> > + LOAD_REG_ADDR(r9, deepsleep_end)
> > +
> > + /* prefecth TLB */
> > +#define CCSR_GPIO1_GPDAT 0x130008
> > +#define CCSR_GPIO1_GPDAT_29 0x4
> > + LOAD_REG_IMMEDIATE(r11, CCSR_GPIO1_GPDAT)
> > + add r11, r31, r11
> > + lwz r10, 0(r11)
> > +
> > +#define CCSR_RCPM_PCPH15SETR 0xe20b4
> > +#define CCSR_RCPM_PCPH15SETR_CORE0 0x1
> > + LOAD_REG_IMMEDIATE(r12, CCSR_RCPM_PCPH15SETR)
> > + add r12, r31, r12
> > + lwz r10, 0(r12)
> > +
> > +#define CCSR_DDR_SDRAM_CFG_2 0x8114
> > +#define CCSR_DDR_SDRAM_CFG_2_FRC_SR 0x80000000
> > + LOAD_REG_IMMEDIATE(r13, CCSR_DDR_SDRAM_CFG_2)
> > + add r13, r31, r13
> > + lwz r10, 0(r13)
> > +
> > +#define DCSR_EPU_EPGCR 0x000
> > +#define DCSR_EPU_EPGCR_GCE 0x80000000
> > + li r14, DCSR_EPU_EPGCR
> > + add r14, r30, r14
> > + lwz r10, 0(r14)
> > +
> > +#define DCSR_EPU_EPECR15 0x33C
> > +#define DCSR_EPU_EPECR15_IC0 0x80000000
> > + li r15, DCSR_EPU_EPECR15
> > + add r15, r30, r15
> > + lwz r10, 0(r15)
> > +
> > +#define CCSR_SCFG_QMCRDTRSTCR 0xfc40c
> > +#define CCSR_SCFG_QMCRDTRSTCR_CRDTRST 0x80000000
> > + LOAD_REG_IMMEDIATE(r16, CCSR_SCFG_QMCRDTRSTCR)
> > + add r16, r31, r16
> > + lwz r10, 0(r16)
> > +
> > +/*
> > + * There are two kind of register maps, one for CPLD and the other for FPGA
> > + */
> > +#define CPLD_MISCCSR 0x17
> > +#define CPLD_MISCCSR_SLEEPEN 0x40
> > +#define QIXIS_PWR_CTL2 0x21
> > +#define QIXIS_PWR_CTL2_PCTL 0x2
> > + PPC_LCMPI 0, r28, FPGA_FLAG
> > + beq 20f
> > + addi r29, r29, CPLD_MISCCSR
> > +20:
> > + addi r29, r29, QIXIS_PWR_CTL2
> > + lbz r10, 0(r29)
>
>
> Again, this is not marked as a board-specific file. How do you expect
> customers to adapt this mechanism to their boards?
Will add comment.
>
> > +
> > + /* prefecth code to cache so that executing code after disable DDR */
> > +1: lwz r3, 0(r8)
> > + addi r8, r8, 4
> > + cmpw r8, r9
> > + blt 1b
> > + msync
>
> Instructions don't execute from dcache... I guess you're assuming it
> will allocate in, and stay in, L2/CPC. It'd be safer to lock those
> cache lines in icache, or copy the code to SRAM.
Yes, they should be in L2/CPC. Will try to lock them in icache.
>
> > + FSL_DIS_ALL_IRQ
> > +
> > + /*
> > + * Place DDR controller in self refresh mode.
> > + * From here on, DDR can't be access any more.
> > + */
> > + lwz r10, 0(r13)
> > + oris r10, r10, CCSR_DDR_SDRAM_CFG_2_FRC_SR@h
> > + stw r10, 0(r13)
> > +
> > + /* can't call udelay() here, so use a macro to delay */
> > + FSLDELAY(50)
>
> A timebase loop doesn't require accessing DDR.
Don't wish to jump at this time. Maybe cause problems.
>
> You also probably want to do a "sync, readback, data dependency, isync"
> sequence to make sure that the store has hit CCSR before you begin your
> delay (or is a delay required at all if you do that?).
Yes. It is safer with a sync sequence.
The DDR controller need some time to signal the external DDR modules to
enter self refresh mode.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-12 10:40 ` Chenhui Zhao
@ 2014-03-14 23:18 ` Scott Wood
2014-03-17 11:19 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-14 23:18 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Wed, 2014-03-12 at 18:40 +0800, Chenhui Zhao wrote:
> On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > From: Zhao Chenhui <chenhui.zhao@freescale.com>
> > >
> > > T1040 supports 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 will be prefetched.
> > >
> > > Due to the different initialization code between 32-bit and 64-bit, they
> > > have seperate resume entry and precedure.
> > >
> > > The feature supports 32-bit and 64-bit kernel mode.
> > >
> > > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > ---
> > > arch/powerpc/include/asm/booke_save_regs.h | 3 +
> > > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
> > > arch/powerpc/kernel/head_fsl_booke.S | 30 +++
> > > arch/powerpc/platforms/85xx/Makefile | 2 +-
> > > arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
> > > arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
> > > arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
> > > arch/powerpc/sysdev/fsl_soc.h | 7 +
> > > 8 files changed, 592 insertions(+), 1 deletions(-)
> > > create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> > > create mode 100644 arch/powerpc/platforms/85xx/sleep.S
> > >
> > > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > > index 87c357a..37c1f6c 100644
> > > --- a/arch/powerpc/include/asm/booke_save_regs.h
> > > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > > @@ -88,6 +88,9 @@
> > > #define HIBERNATION_FLAG 1
> > > #define DEEPSLEEP_FLAG 2
> > >
> > > +#define CPLD_FLAG 1
> > > +#define FPGA_FLAG 2
> >
> > What is this?
>
> We have two kind of boards, QDS and RDB.
> They have different register map. Use the flag to indicate the current board is using which kind
> of register map.
CPLD versus FPGA is not a meaningful difference. We don't care what
technology is used to implement programmable logic -- we care what
programming interface is exposed. Customers will have their own boards
that will likely not imitate either of these programming interfaces, but
what they do have will still probably be implemented in a CPLD or FPGA.
Likewise, Freescale may have future reference boards whose CPLD/FPGA is
not compatible.
So use better naming, and structure the code so it's easy to plug in
implementations for new or custom boards.
> > > diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> > > index 20204fe..3285752 100644
> > > --- a/arch/powerpc/kernel/head_fsl_booke.S
> > > +++ b/arch/powerpc/kernel/head_fsl_booke.S
> > > @@ -162,6 +162,19 @@ _ENTRY(__early_start)
> > > #include "fsl_booke_entry_mapping.S"
> > > #undef ENTRY_MAPPING_BOOT_SETUP
> > >
> > > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > > + /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
> > > + LOAD_REG_ADDR(r4, deep_sleep_flag)
> > > + lwz r3, 0(r4)
> > > + cmpwi r3, 0
> > > + beq 11f
> > > + /* clear deep_sleep_flag */
> > > + li r3, 0
> > > + stw r3, 0(r4)
> > > + b fsl_deepsleep_resume
> > > +11:
> > > +#endif
> >
> > Why do you come in via the normal kernel entry, versus specifying a
> > direct entry point for deep sleep resume? How does U-Boot even know
> > what the normal entry is when resuming?
>
> I wish to return to a specified point (like 64-bit mode), but the code in
> fsl_booke_entry_mapping.S only can run in the first page. Because it
> only setups a temp mapping of 4KB.
Why do you need the entry mapping on 32-bit but not 64-bit?
>
> > > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > > +_ENTRY(__entry_deep_sleep)
> > > +/*
> > > + * Bootloader will jump to here when resuming from deep sleep.
> > > + * After executing the init code in fsl_booke_entry_mapping.S,
> > > + * will jump to the real resume entry.
> > > + */
> > > + li r8, 1
> > > + bl 12f
> > > +12: mflr r9
> > > + addi r9, r9, (deep_sleep_flag - 12b)
> > > + stw r8, 0(r9)
> > > + b __early_start
> > > +deep_sleep_flag:
> > > + .long 0
> > > +#endif
> >
> > It's a bit ambiguous to say "entry_deep_sleep" when it's resuming rather
> > than entering...
>
> How about __fsl_entry_resume?
fsl_booke_deep_sleep_resume
> > > +#define FSLDELAY(count) \
> > > + li r3, (count)@l; \
> > > + slwi r3, r3, 10; \
> > > + mtctr r3; \
> > > +101: nop; \
> > > + bdnz 101b;
> >
> > You don't need a namespace prefix on local macros in a non-header file.
> >
> > Is the timebase stopped where you're calling this from?
>
> No. My purpose is to avoid jump in the last stage of entering deep sleep.
> Jump may cause problem at that time.
"bdnz" is a jump.
What problems do you think a jump will cause?
> > You also probably want to do a "sync, readback, data dependency, isync"
> > sequence to make sure that the store has hit CCSR before you begin your
> > delay (or is a delay required at all if you do that?).
>
> Yes. It is safer with a sync sequence.
>
> The DDR controller need some time to signal the external DDR modules to
> enter self refresh mode.
Is it documented how much time it requires?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-14 23:18 ` Scott Wood
@ 2014-03-17 11:19 ` Chenhui Zhao
2014-03-18 22:42 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-17 11:19 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Fri, Mar 14, 2014 at 06:18:27PM -0500, Scott Wood wrote:
> On Wed, 2014-03-12 at 18:40 +0800, Chenhui Zhao wrote:
> > On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > From: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > >
> > > > T1040 supports 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 will be prefetched.
> > > >
> > > > Due to the different initialization code between 32-bit and 64-bit, they
> > > > have seperate resume entry and precedure.
> > > >
> > > > The feature supports 32-bit and 64-bit kernel mode.
> > > >
> > > > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > > ---
> > > > arch/powerpc/include/asm/booke_save_regs.h | 3 +
> > > > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
> > > > arch/powerpc/kernel/head_fsl_booke.S | 30 +++
> > > > arch/powerpc/platforms/85xx/Makefile | 2 +-
> > > > arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
> > > > arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
> > > > arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
> > > > arch/powerpc/sysdev/fsl_soc.h | 7 +
> > > > 8 files changed, 592 insertions(+), 1 deletions(-)
> > > > create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> > > > create mode 100644 arch/powerpc/platforms/85xx/sleep.S
> > > >
> > > > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > > > index 87c357a..37c1f6c 100644
> > > > --- a/arch/powerpc/include/asm/booke_save_regs.h
> > > > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > > > @@ -88,6 +88,9 @@
> > > > #define HIBERNATION_FLAG 1
> > > > #define DEEPSLEEP_FLAG 2
> > > >
> > > > +#define CPLD_FLAG 1
> > > > +#define FPGA_FLAG 2
> > >
> > > What is this?
> >
> > We have two kind of boards, QDS and RDB.
> > They have different register map. Use the flag to indicate the current board is using which kind
> > of register map.
>
> CPLD versus FPGA is not a meaningful difference. We don't care what
> technology is used to implement programmable logic -- we care what
> programming interface is exposed. Customers will have their own boards
> that will likely not imitate either of these programming interfaces, but
> what they do have will still probably be implemented in a CPLD or FPGA.
> Likewise, Freescale may have future reference boards whose CPLD/FPGA is
> not compatible.
Will use a better name.
>
> So use better naming, and structure the code so it's easy to plug in
> implementations for new or custom boards.
>
> > > > diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> > > > index 20204fe..3285752 100644
> > > > --- a/arch/powerpc/kernel/head_fsl_booke.S
> > > > +++ b/arch/powerpc/kernel/head_fsl_booke.S
> > > > @@ -162,6 +162,19 @@ _ENTRY(__early_start)
> > > > #include "fsl_booke_entry_mapping.S"
> > > > #undef ENTRY_MAPPING_BOOT_SETUP
> > > >
> > > > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > > > + /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
> > > > + LOAD_REG_ADDR(r4, deep_sleep_flag)
> > > > + lwz r3, 0(r4)
> > > > + cmpwi r3, 0
> > > > + beq 11f
> > > > + /* clear deep_sleep_flag */
> > > > + li r3, 0
> > > > + stw r3, 0(r4)
> > > > + b fsl_deepsleep_resume
> > > > +11:
> > > > +#endif
> > >
> > > Why do you come in via the normal kernel entry, versus specifying a
> > > direct entry point for deep sleep resume? How does U-Boot even know
> > > what the normal entry is when resuming?
> >
> > I wish to return to a specified point (like 64-bit mode), but the code in
> > fsl_booke_entry_mapping.S only can run in the first page. Because it
> > only setups a temp mapping of 4KB.
>
> Why do you need the entry mapping on 32-bit but not 64-bit?
fsl_booke_entry_mapping.S is for 32-bit. 64-bit calls
initial_tlb_book3e() in exceptions-64e.S.
> >
> > > > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > > > +_ENTRY(__entry_deep_sleep)
> > > > +/*
> > > > + * Bootloader will jump to here when resuming from deep sleep.
> > > > + * After executing the init code in fsl_booke_entry_mapping.S,
> > > > + * will jump to the real resume entry.
> > > > + */
> > > > + li r8, 1
> > > > + bl 12f
> > > > +12: mflr r9
> > > > + addi r9, r9, (deep_sleep_flag - 12b)
> > > > + stw r8, 0(r9)
> > > > + b __early_start
> > > > +deep_sleep_flag:
> > > > + .long 0
> > > > +#endif
> > >
> > > It's a bit ambiguous to say "entry_deep_sleep" when it's resuming rather
> > > than entering...
> >
> > How about __fsl_entry_resume?
>
> fsl_booke_deep_sleep_resume
>
> > > > +#define FSLDELAY(count) \
> > > > + li r3, (count)@l; \
> > > > + slwi r3, r3, 10; \
> > > > + mtctr r3; \
> > > > +101: nop; \
> > > > + bdnz 101b;
> > >
> > > You don't need a namespace prefix on local macros in a non-header file.
> > >
> > > Is the timebase stopped where you're calling this from?
> >
> > No. My purpose is to avoid jump in the last stage of entering deep sleep.
> > Jump may cause problem at that time.
>
> "bdnz" is a jump.
>
> What problems do you think a jump will cause?
I mean a far jump which can jump to an address which has not been prefetched in
advance. I wish the code is executed in a restricted environment (predictable code
and address).
>
> > > You also probably want to do a "sync, readback, data dependency, isync"
> > > sequence to make sure that the store has hit CCSR before you begin your
> > > delay (or is a delay required at all if you do that?).
> >
> > Yes. It is safer with a sync sequence.
> >
> > The DDR controller need some time to signal the external DDR modules to
> > enter self refresh mode.
>
> Is it documented how much time it requires?
>
> -Scott
No.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-17 11:19 ` Chenhui Zhao
@ 2014-03-18 22:42 ` Scott Wood
2014-03-19 0:56 ` Chenhui Zhao
0 siblings, 1 reply; 50+ messages in thread
From: Scott Wood @ 2014-03-18 22:42 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Mon, 2014-03-17 at 19:19 +0800, Chenhui Zhao wrote:
> On Fri, Mar 14, 2014 at 06:18:27PM -0500, Scott Wood wrote:
> > On Wed, 2014-03-12 at 18:40 +0800, Chenhui Zhao wrote:
> > > On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> > > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > > From: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > > >
> > > > > T1040 supports 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 will be prefetched.
> > > > >
> > > > > Due to the different initialization code between 32-bit and 64-bit, they
> > > > > have seperate resume entry and precedure.
> > > > >
> > > > > The feature supports 32-bit and 64-bit kernel mode.
> > > > >
> > > > > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > > > ---
> > > > > arch/powerpc/include/asm/booke_save_regs.h | 3 +
> > > > > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
> > > > > arch/powerpc/kernel/head_fsl_booke.S | 30 +++
> > > > > arch/powerpc/platforms/85xx/Makefile | 2 +-
> > > > > arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
> > > > > arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
> > > > > arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
> > > > > arch/powerpc/sysdev/fsl_soc.h | 7 +
> > > > > 8 files changed, 592 insertions(+), 1 deletions(-)
> > > > > create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> > > > > create mode 100644 arch/powerpc/platforms/85xx/sleep.S
> > > > >
> > > > > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > > > > index 87c357a..37c1f6c 100644
> > > > > --- a/arch/powerpc/include/asm/booke_save_regs.h
> > > > > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > > > > @@ -88,6 +88,9 @@
> > > > > #define HIBERNATION_FLAG 1
> > > > > #define DEEPSLEEP_FLAG 2
> > > > >
> > > > > +#define CPLD_FLAG 1
> > > > > +#define FPGA_FLAG 2
> > > >
> > > > What is this?
> > >
> > > We have two kind of boards, QDS and RDB.
> > > They have different register map. Use the flag to indicate the current board is using which kind
> > > of register map.
> >
> > CPLD versus FPGA is not a meaningful difference. We don't care what
> > technology is used to implement programmable logic -- we care what
> > programming interface is exposed. Customers will have their own boards
> > that will likely not imitate either of these programming interfaces, but
> > what they do have will still probably be implemented in a CPLD or FPGA.
> > Likewise, Freescale may have future reference boards whose CPLD/FPGA is
> > not compatible.
>
> Will use a better name.
>
> >
> > So use better naming, and structure the code so it's easy to plug in
> > implementations for new or custom boards.
> >
> > > > > diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> > > > > index 20204fe..3285752 100644
> > > > > --- a/arch/powerpc/kernel/head_fsl_booke.S
> > > > > +++ b/arch/powerpc/kernel/head_fsl_booke.S
> > > > > @@ -162,6 +162,19 @@ _ENTRY(__early_start)
> > > > > #include "fsl_booke_entry_mapping.S"
> > > > > #undef ENTRY_MAPPING_BOOT_SETUP
> > > > >
> > > > > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > > > > + /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
> > > > > + LOAD_REG_ADDR(r4, deep_sleep_flag)
> > > > > + lwz r3, 0(r4)
> > > > > + cmpwi r3, 0
> > > > > + beq 11f
> > > > > + /* clear deep_sleep_flag */
> > > > > + li r3, 0
> > > > > + stw r3, 0(r4)
> > > > > + b fsl_deepsleep_resume
> > > > > +11:
> > > > > +#endif
> > > >
> > > > Why do you come in via the normal kernel entry, versus specifying a
> > > > direct entry point for deep sleep resume? How does U-Boot even know
> > > > what the normal entry is when resuming?
> > >
> > > I wish to return to a specified point (like 64-bit mode), but the code in
> > > fsl_booke_entry_mapping.S only can run in the first page. Because it
> > > only setups a temp mapping of 4KB.
> >
> > Why do you need the entry mapping on 32-bit but not 64-bit?
>
> fsl_booke_entry_mapping.S is for 32-bit. 64-bit calls
> initial_tlb_book3e() in exceptions-64e.S.
The answer I was looking for is that __entry_deep_sleep calls
start_initialization_book3e which calls the code to handle it.
But why is it driven from sleep.S on 64-bit but not on 32-bit? Why
can't you make it so that the 32-bit TLB setup can be called into in a
similar manner?
> > > > > +#define FSLDELAY(count) \
> > > > > + li r3, (count)@l; \
> > > > > + slwi r3, r3, 10; \
> > > > > + mtctr r3; \
> > > > > +101: nop; \
> > > > > + bdnz 101b;
> > > >
> > > > You don't need a namespace prefix on local macros in a non-header file.
> > > >
> > > > Is the timebase stopped where you're calling this from?
> > >
> > > No. My purpose is to avoid jump in the last stage of entering deep sleep.
> > > Jump may cause problem at that time.
> >
> > "bdnz" is a jump.
> >
> > What problems do you think a jump will cause?
>
> I mean a far jump which can jump to an address which has not been prefetched in
> advance. I wish the code is executed in a restricted environment (predictable code
> and address).
Why would a timebase loop require a "far" jump?
> > > > You also probably want to do a "sync, readback, data dependency, isync"
> > > > sequence to make sure that the store has hit CCSR before you begin your
> > > > delay (or is a delay required at all if you do that?).
> > >
> > > Yes. It is safer with a sync sequence.
> > >
> > > The DDR controller need some time to signal the external DDR modules to
> > > enter self refresh mode.
> >
> > Is it documented how much time it requires?
> >
> > -Scott
>
> No.
How do you know the current delay is adequate in all circumstances (e.g
clock speeds), much less on future chips? Is it documented that a delay
is needed at all, or is this just something that appeared to make it
work? If the latter, what happens if you put the synchronization in,
but leave out the delay?
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-18 22:42 ` Scott Wood
@ 2014-03-19 0:56 ` Chenhui Zhao
2014-03-20 23:33 ` Scott Wood
0 siblings, 1 reply; 50+ messages in thread
From: Chenhui Zhao @ 2014-03-19 0:56 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Tue, Mar 18, 2014 at 05:42:09PM -0500, Scott Wood wrote:
> On Mon, 2014-03-17 at 19:19 +0800, Chenhui Zhao wrote:
> > On Fri, Mar 14, 2014 at 06:18:27PM -0500, Scott Wood wrote:
> > > On Wed, 2014-03-12 at 18:40 +0800, Chenhui Zhao wrote:
> > > > On Tue, Mar 11, 2014 at 08:10:24PM -0500, Scott Wood wrote:
> > > > > On Fri, 2014-03-07 at 12:58 +0800, Chenhui Zhao wrote:
> > > > > > From: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > > > >
> > > > > > T1040 supports 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 will be prefetched.
> > > > > >
> > > > > > Due to the different initialization code between 32-bit and 64-bit, they
> > > > > > have seperate resume entry and precedure.
> > > > > >
> > > > > > The feature supports 32-bit and 64-bit kernel mode.
> > > > > >
> > > > > > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > > > > > ---
> > > > > > arch/powerpc/include/asm/booke_save_regs.h | 3 +
> > > > > > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 17 ++
> > > > > > arch/powerpc/kernel/head_fsl_booke.S | 30 +++
> > > > > > arch/powerpc/platforms/85xx/Makefile | 2 +-
> > > > > > arch/powerpc/platforms/85xx/deepsleep.c | 201 +++++++++++++++++++
> > > > > > arch/powerpc/platforms/85xx/qoriq_pm.c | 38 ++++
> > > > > > arch/powerpc/platforms/85xx/sleep.S | 295 ++++++++++++++++++++++++++++
> > > > > > arch/powerpc/sysdev/fsl_soc.h | 7 +
> > > > > > 8 files changed, 592 insertions(+), 1 deletions(-)
> > > > > > create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c
> > > > > > create mode 100644 arch/powerpc/platforms/85xx/sleep.S
> > > > > >
> > > > > > diff --git a/arch/powerpc/include/asm/booke_save_regs.h b/arch/powerpc/include/asm/booke_save_regs.h
> > > > > > index 87c357a..37c1f6c 100644
> > > > > > --- a/arch/powerpc/include/asm/booke_save_regs.h
> > > > > > +++ b/arch/powerpc/include/asm/booke_save_regs.h
> > > > > > @@ -88,6 +88,9 @@
> > > > > > #define HIBERNATION_FLAG 1
> > > > > > #define DEEPSLEEP_FLAG 2
> > > > > >
> > > > > > +#define CPLD_FLAG 1
> > > > > > +#define FPGA_FLAG 2
> > > > >
> > > > > What is this?
> > > >
> > > > We have two kind of boards, QDS and RDB.
> > > > They have different register map. Use the flag to indicate the current board is using which kind
> > > > of register map.
> > >
> > > CPLD versus FPGA is not a meaningful difference. We don't care what
> > > technology is used to implement programmable logic -- we care what
> > > programming interface is exposed. Customers will have their own boards
> > > that will likely not imitate either of these programming interfaces, but
> > > what they do have will still probably be implemented in a CPLD or FPGA.
> > > Likewise, Freescale may have future reference boards whose CPLD/FPGA is
> > > not compatible.
> >
> > Will use a better name.
> >
> > >
> > > So use better naming, and structure the code so it's easy to plug in
> > > implementations for new or custom boards.
> > >
> > > > > > diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
> > > > > > index 20204fe..3285752 100644
> > > > > > --- a/arch/powerpc/kernel/head_fsl_booke.S
> > > > > > +++ b/arch/powerpc/kernel/head_fsl_booke.S
> > > > > > @@ -162,6 +162,19 @@ _ENTRY(__early_start)
> > > > > > #include "fsl_booke_entry_mapping.S"
> > > > > > #undef ENTRY_MAPPING_BOOT_SETUP
> > > > > >
> > > > > > +#if defined(CONFIG_SUSPEND) && defined(CONFIG_FSL_CORENET_RCPM)
> > > > > > + /* if deep_sleep_flag != 0, jump to the deep sleep resume entry */
> > > > > > + LOAD_REG_ADDR(r4, deep_sleep_flag)
> > > > > > + lwz r3, 0(r4)
> > > > > > + cmpwi r3, 0
> > > > > > + beq 11f
> > > > > > + /* clear deep_sleep_flag */
> > > > > > + li r3, 0
> > > > > > + stw r3, 0(r4)
> > > > > > + b fsl_deepsleep_resume
> > > > > > +11:
> > > > > > +#endif
> > > > >
> > > > > Why do you come in via the normal kernel entry, versus specifying a
> > > > > direct entry point for deep sleep resume? How does U-Boot even know
> > > > > what the normal entry is when resuming?
> > > >
> > > > I wish to return to a specified point (like 64-bit mode), but the code in
> > > > fsl_booke_entry_mapping.S only can run in the first page. Because it
> > > > only setups a temp mapping of 4KB.
> > >
> > > Why do you need the entry mapping on 32-bit but not 64-bit?
> >
> > fsl_booke_entry_mapping.S is for 32-bit. 64-bit calls
> > initial_tlb_book3e() in exceptions-64e.S.
>
> The answer I was looking for is that __entry_deep_sleep calls
> start_initialization_book3e which calls the code to handle it.
>
> But why is it driven from sleep.S on 64-bit but not on 32-bit? Why
> can't you make it so that the 32-bit TLB setup can be called into in a
> similar manner?
Yes. I also wish to do like this. As I mentioned, the problem in 32-bit
is that the TLB setup code in fsl_booke_entry_mapping.S only setups a temp
mapping of 4KB, so these code only can run in this 4KB address space. But the
code in sleep.S is outside of the 4KB space. So can't put the TLB setup
code in sleep.S. There are two method to solve it.
1) The current method is running the TLB setup code of fsl_booke_entry_mapping.S in the 4KB
space, then jump to the code of sleep.S.
2) extend the temp mapping space in the TLB setup code to cover kernel, say 4MB or 8MB. But
not sure if there are any side effects.
>
> > > > > > +#define FSLDELAY(count) \
> > > > > > + li r3, (count)@l; \
> > > > > > + slwi r3, r3, 10; \
> > > > > > + mtctr r3; \
> > > > > > +101: nop; \
> > > > > > + bdnz 101b;
> > > > >
> > > > > You don't need a namespace prefix on local macros in a non-header file.
> > > > >
> > > > > Is the timebase stopped where you're calling this from?
> > > >
> > > > No. My purpose is to avoid jump in the last stage of entering deep sleep.
> > > > Jump may cause problem at that time.
> > >
> > > "bdnz" is a jump.
> > >
> > > What problems do you think a jump will cause?
> >
> > I mean a far jump which can jump to an address which has not been prefetched in
> > advance. I wish the code is executed in a restricted environment (predictable code
> > and address).
>
> Why would a timebase loop require a "far" jump?
I mean there is far jump in udely().
Do you mean using a timebase loop in the macro FSLDELAY? If so, I agree.
>
> > > > > You also probably want to do a "sync, readback, data dependency, isync"
> > > > > sequence to make sure that the store has hit CCSR before you begin your
> > > > > delay (or is a delay required at all if you do that?).
> > > >
> > > > Yes. It is safer with a sync sequence.
> > > >
> > > > The DDR controller need some time to signal the external DDR modules to
> > > > enter self refresh mode.
> > >
> > > Is it documented how much time it requires?
> > >
> > > -Scott
> >
> > No.
>
> How do you know the current delay is adequate in all circumstances (e.g
> clock speeds), much less on future chips? Is it documented that a delay
> is needed at all, or is this just something that appeared to make it
> work? If the latter, what happens if you put the synchronization in,
> but leave out the delay?
>
> -Scott
The code controls external parts (FPGA/CPLD, DDR module) to act, and
the sequent code must wait until external parts complete. We can't get
an ack from external parts, so use delay to make sure the sequence and
insert enough time to wait.
-Chenhui
^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH 9/9] powerpc/pm: support deep sleep feature on T1040
2014-03-19 0:56 ` Chenhui Zhao
@ 2014-03-20 23:33 ` Scott Wood
0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2014-03-20 23:33 UTC (permalink / raw)
To: Chenhui Zhao; +Cc: linuxppc-dev, linux-kernel, Jason.Jin
On Wed, 2014-03-19 at 08:56 +0800, Chenhui Zhao wrote:
> On Tue, Mar 18, 2014 at 05:42:09PM -0500, Scott Wood wrote:
> > On Mon, 2014-03-17 at 19:19 +0800, Chenhui Zhao wrote:
> > > On Fri, Mar 14, 2014 at 06:18:27PM -0500, Scott Wood wrote:
> > > > Why do you need the entry mapping on 32-bit but not 64-bit?
> > >
> > > fsl_booke_entry_mapping.S is for 32-bit. 64-bit calls
> > > initial_tlb_book3e() in exceptions-64e.S.
> >
> > The answer I was looking for is that __entry_deep_sleep calls
> > start_initialization_book3e which calls the code to handle it.
> >
> > But why is it driven from sleep.S on 64-bit but not on 32-bit? Why
> > can't you make it so that the 32-bit TLB setup can be called into in a
> > similar manner?
>
> Yes. I also wish to do like this. As I mentioned, the problem in 32-bit
> is that the TLB setup code in fsl_booke_entry_mapping.S only setups a temp
> mapping of 4KB, so these code only can run in this 4KB address space. But the
> code in sleep.S is outside of the 4KB space. So can't put the TLB setup
> code in sleep.S. There are two method to solve it.
> 1) The current method is running the TLB setup code of fsl_booke_entry_mapping.S in the 4KB
> space, then jump to the code of sleep.S.
> 2) extend the temp mapping space in the TLB setup code to cover kernel, say 4MB or 8MB. But
> not sure if there are any side effects.
fsl_booke_entry_mapping.S creates a 64M entry. The 4K entry is only
temporary while in AS1 -- it shouldn't matter if the address you return
to when leaving fsl_booke_entry_mapping.S is outside the 4K, as long as
it's within the 64M entry.
Or am I missing something?
> > > > > > > +#define FSLDELAY(count) \
> > > > > > > + li r3, (count)@l; \
> > > > > > > + slwi r3, r3, 10; \
> > > > > > > + mtctr r3; \
> > > > > > > +101: nop; \
> > > > > > > + bdnz 101b;
> > > > > >
> > > > > > You don't need a namespace prefix on local macros in a non-header file.
> > > > > >
> > > > > > Is the timebase stopped where you're calling this from?
> > > > >
> > > > > No. My purpose is to avoid jump in the last stage of entering deep sleep.
> > > > > Jump may cause problem at that time.
> > > >
> > > > "bdnz" is a jump.
> > > >
> > > > What problems do you think a jump will cause?
> > >
> > > I mean a far jump which can jump to an address which has not been prefetched in
> > > advance. I wish the code is executed in a restricted environment (predictable code
> > > and address).
> >
> > Why would a timebase loop require a "far" jump?
>
> I mean there is far jump in udely().
>
> Do you mean using a timebase loop in the macro FSLDELAY? If so, I agree.
Yes, I meant a timebase loop, not udelay().
> > > > > > You also probably want to do a "sync, readback, data dependency, isync"
> > > > > > sequence to make sure that the store has hit CCSR before you begin your
> > > > > > delay (or is a delay required at all if you do that?).
> > > > >
> > > > > Yes. It is safer with a sync sequence.
> > > > >
> > > > > The DDR controller need some time to signal the external DDR modules to
> > > > > enter self refresh mode.
> > > >
> > > > Is it documented how much time it requires?
> > > >
> > > > -Scott
> > >
> > > No.
> >
> > How do you know the current delay is adequate in all circumstances (e.g
> > clock speeds), much less on future chips? Is it documented that a delay
> > is needed at all, or is this just something that appeared to make it
> > work? If the latter, what happens if you put the synchronization in,
> > but leave out the delay?
> >
> > -Scott
>
> The code controls external parts (FPGA/CPLD, DDR module) to act, and
> the sequent code must wait until external parts complete. We can't get
> an ack from external parts, so use delay to make sure the sequence and
> insert enough time to wait.
It would be good if you could get the hardware designers to provide an
upper bound for how long we need to wait.
-Scott
^ permalink raw reply [flat|nested] 50+ messages in thread