All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-26 10:25 ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel, galak, leoli

Do hardware timebase sync. Firstly, stop all timebases, and transfer
the timebase value of the boot core to the other core. Finally,
start all timebases.

Only apply to dual-core chips, such as MPC8572, P2020, etc.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
Changes for v6:
 * added 85xx_TB_SYNC
 * added isync() after set_tb()
 * removed extra entries from mpc85xx_smp_guts_ids

 arch/powerpc/include/asm/fsl_guts.h |    2 +
 arch/powerpc/platforms/85xx/Kconfig |    5 ++
 arch/powerpc/platforms/85xx/smp.c   |   84 +++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index aa4c488..dd5ba2c 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -48,6 +48,8 @@ struct ccsr_guts {
         __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
         u8	res06c[0x70 - 0x6c];
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
+#define CCSR_GUTS_DEVDISR_TB1	0x00001000
+#define CCSR_GUTS_DEVDISR_TB0	0x00004000
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
 	u8	res078[0x7c - 0x78];
 	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index f000d81..8dd7147 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 85xx_TB_SYNC if KEXEC
 	default y
 
 if FSL_SOC_BOOKE
@@ -267,3 +268,7 @@ endif # FSL_SOC_BOOKE
 
 config TQM85xx
 	bool
+
+config 85xx_TB_SYNC
+	bool
+	default n
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index ff42490..edb0cad 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -24,6 +24,7 @@
 #include <asm/mpic.h>
 #include <asm/cacheflush.h>
 #include <asm/dbell.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/mpic.h>
@@ -42,6 +43,69 @@ extern void __early_start(void);
 #define NUM_BOOT_ENTRY		8
 #define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
 
+#ifdef CONFIG_85xx_TB_SYNC
+static struct ccsr_guts __iomem *guts;
+static u64 timebase;
+static int tb_req;
+static int tb_valid;
+
+static void mpc85xx_timebase_freeze(int freeze)
+{
+	unsigned int mask;
+
+	if (!guts)
+		return;
+
+	mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
+	if (freeze)
+		setbits32(&guts->devdisr, mask);
+	else
+		clrbits32(&guts->devdisr, mask);
+
+	in_be32(&guts->devdisr);
+}
+
+static void mpc85xx_give_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	while (!tb_req)
+		barrier();
+	tb_req = 0;
+
+	mpc85xx_timebase_freeze(1);
+	timebase = get_tb();
+	mb();
+	tb_valid = 1;
+
+	while (tb_valid)
+		barrier();
+
+	mpc85xx_timebase_freeze(0);
+
+	local_irq_restore(flags);
+}
+
+static void mpc85xx_take_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	tb_req = 1;
+	while (!tb_valid)
+		barrier();
+
+	set_tb(timebase >> 32, timebase & 0xffffffff);
+	isync();
+	tb_valid = 0;
+
+	local_irq_restore(flags);
+}
+#endif
+
 static int __init
 smp_85xx_kick_cpu(int nr)
 {
@@ -228,6 +292,16 @@ smp_85xx_setup_cpu(int cpu_nr)
 		doorbell_setup_this_cpu();
 }
 
+static const struct of_device_id mpc85xx_smp_guts_ids[] = {
+	{ .compatible = "fsl,mpc8572-guts", },
+	{ .compatible = "fsl,p1020-guts", },
+	{ .compatible = "fsl,p1021-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{ .compatible = "fsl,p1023-guts", },
+	{ .compatible = "fsl,p2020-guts", },
+	{},
+};
+
 void __init mpc85xx_smp_init(void)
 {
 	struct device_node *np;
@@ -249,6 +323,16 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
 	}
 
+	np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
+	if (np) {
+#ifdef CONFIG_85xx_TB_SYNC
+		guts = of_iomap(np, 0);
+		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+#endif
+		of_node_put(np);
+	}
+
 	smp_ops = &smp_85xx_ops;
 
 #ifdef CONFIG_KEXEC
-- 
1.6.4.1



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

* [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-26 10:25 ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel

Do hardware timebase sync. Firstly, stop all timebases, and transfer
the timebase value of the boot core to the other core. Finally,
start all timebases.

Only apply to dual-core chips, such as MPC8572, P2020, etc.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
Changes for v6:
 * added 85xx_TB_SYNC
 * added isync() after set_tb()
 * removed extra entries from mpc85xx_smp_guts_ids

 arch/powerpc/include/asm/fsl_guts.h |    2 +
 arch/powerpc/platforms/85xx/Kconfig |    5 ++
 arch/powerpc/platforms/85xx/smp.c   |   84 +++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index aa4c488..dd5ba2c 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -48,6 +48,8 @@ struct ccsr_guts {
         __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
         u8	res06c[0x70 - 0x6c];
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
+#define CCSR_GUTS_DEVDISR_TB1	0x00001000
+#define CCSR_GUTS_DEVDISR_TB0	0x00004000
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
 	u8	res078[0x7c - 0x78];
 	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index f000d81..8dd7147 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 85xx_TB_SYNC if KEXEC
 	default y
 
 if FSL_SOC_BOOKE
@@ -267,3 +268,7 @@ endif # FSL_SOC_BOOKE
 
 config TQM85xx
 	bool
+
+config 85xx_TB_SYNC
+	bool
+	default n
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index ff42490..edb0cad 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -24,6 +24,7 @@
 #include <asm/mpic.h>
 #include <asm/cacheflush.h>
 #include <asm/dbell.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/mpic.h>
@@ -42,6 +43,69 @@ extern void __early_start(void);
 #define NUM_BOOT_ENTRY		8
 #define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
 
+#ifdef CONFIG_85xx_TB_SYNC
+static struct ccsr_guts __iomem *guts;
+static u64 timebase;
+static int tb_req;
+static int tb_valid;
+
+static void mpc85xx_timebase_freeze(int freeze)
+{
+	unsigned int mask;
+
+	if (!guts)
+		return;
+
+	mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
+	if (freeze)
+		setbits32(&guts->devdisr, mask);
+	else
+		clrbits32(&guts->devdisr, mask);
+
+	in_be32(&guts->devdisr);
+}
+
+static void mpc85xx_give_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	while (!tb_req)
+		barrier();
+	tb_req = 0;
+
+	mpc85xx_timebase_freeze(1);
+	timebase = get_tb();
+	mb();
+	tb_valid = 1;
+
+	while (tb_valid)
+		barrier();
+
+	mpc85xx_timebase_freeze(0);
+
+	local_irq_restore(flags);
+}
+
+static void mpc85xx_take_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	tb_req = 1;
+	while (!tb_valid)
+		barrier();
+
+	set_tb(timebase >> 32, timebase & 0xffffffff);
+	isync();
+	tb_valid = 0;
+
+	local_irq_restore(flags);
+}
+#endif
+
 static int __init
 smp_85xx_kick_cpu(int nr)
 {
@@ -228,6 +292,16 @@ smp_85xx_setup_cpu(int cpu_nr)
 		doorbell_setup_this_cpu();
 }
 
+static const struct of_device_id mpc85xx_smp_guts_ids[] = {
+	{ .compatible = "fsl,mpc8572-guts", },
+	{ .compatible = "fsl,p1020-guts", },
+	{ .compatible = "fsl,p1021-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{ .compatible = "fsl,p1023-guts", },
+	{ .compatible = "fsl,p2020-guts", },
+	{},
+};
+
 void __init mpc85xx_smp_init(void)
 {
 	struct device_node *np;
@@ -249,6 +323,16 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
 	}
 
+	np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
+	if (np) {
+#ifdef CONFIG_85xx_TB_SYNC
+		guts = of_iomap(np, 0);
+		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+#endif
+		of_node_put(np);
+	}
+
 	smp_ops = &smp_85xx_ops;
 
 #ifdef CONFIG_KEXEC
-- 
1.6.4.1

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

* [PATCH v6 2/5] powerpc/85xx: add HOTPLUG_CPU support
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-26 10:25   ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel, galak, leoli

From: Li Yang <leoli@freescale.com>

Add support to disable and re-enable individual cores at runtime
on MPC85xx/QorIQ SMP machines. Currently support e500v1/e500v2 core.

MPC85xx machines use ePAPR spin-table in boot page for CPU kick-off.
This patch uses the boot page from bootloader to boot core at runtime.
It supports 32-bit and 36-bit physical address.

Add generic_set_cpu_up() to set cpu_state as CPU_UP_PREPARE in kick_cpu().

Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
Changes for v6:
 * do not guard __flush_disable_L1() by ifdefs
 * added isync() after mtspr()

 arch/powerpc/Kconfig                  |    6 +-
 arch/powerpc/include/asm/cacheflush.h |    2 +
 arch/powerpc/include/asm/smp.h        |    2 +
 arch/powerpc/kernel/head_fsl_booke.S  |   28 +++++++
 arch/powerpc/kernel/smp.c             |   10 +++
 arch/powerpc/platforms/85xx/Kconfig   |    2 +-
 arch/powerpc/platforms/85xx/smp.c     |  137 ++++++++++++++++++++++++---------
 7 files changed, 147 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 38786c8..d6bacbe 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -220,7 +220,8 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
 	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-		   (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x
+		   (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+		   || 44x || 40x
 
 config PPC_DCR_NATIVE
 	bool
@@ -331,7 +332,8 @@ config SWIOTLB
 
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
-	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
+	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
+	PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
 	---help---
 	  Say Y here to be able to disable and re-enable individual
 	  CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ab9e402..b843e35 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,6 +30,8 @@ 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);
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ebc24dc..e807e9d 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -65,6 +65,7 @@ int generic_cpu_disable(void);
 void generic_cpu_die(unsigned int cpu);
 void generic_mach_cpu_die(void);
 void generic_set_cpu_dead(unsigned int cpu);
+void generic_set_cpu_up(unsigned int cpu);
 int generic_check_cpu_restart(unsigned int cpu);
 #endif
 
@@ -190,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
+extern void __early_start(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index de80e0f..be0261b 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -996,6 +996,34 @@ _GLOBAL(flush_dcache_L1)
 
 	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/kernel/smp.c b/arch/powerpc/kernel/smp.c
index d9f9441..e0ffe03 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -423,6 +423,16 @@ void generic_set_cpu_dead(unsigned int cpu)
 	per_cpu(cpu_state, cpu) = CPU_DEAD;
 }
 
+/*
+ * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise
+ * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(),
+ * which makes the delay in generic_cpu_die() not happen.
+ */
+void generic_set_cpu_up(unsigned int cpu)
+{
+	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+}
+
 int generic_check_cpu_restart(unsigned int cpu)
 {
 	return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE;
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 8dd7147..e4beb34 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -8,7 +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 85xx_TB_SYNC if KEXEC
+	select 85xx_TB_SYNC if KEXEC || HOTPLUG_CPU
 	default y
 
 if FSL_SOC_BOOKE
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index edb0cad..2854bfa 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -2,7 +2,7 @@
  * Author: Andy Fleming <afleming@freescale.com>
  * 	   Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2006-2008, 2011 Freescale Semiconductor Inc.
+ * Copyright 2006-2008, 2011-2012 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
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/kexec.h>
 #include <linux/highmem.h>
+#include <linux/cpu.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -30,18 +31,14 @@
 #include <sysdev/mpic.h>
 #include "smp.h"
 
-extern void __early_start(void);
-
-#define BOOT_ENTRY_ADDR_UPPER	0
-#define BOOT_ENTRY_ADDR_LOWER	1
-#define BOOT_ENTRY_R3_UPPER	2
-#define BOOT_ENTRY_R3_LOWER	3
-#define BOOT_ENTRY_RESV		4
-#define BOOT_ENTRY_PIR		5
-#define BOOT_ENTRY_R6_UPPER	6
-#define BOOT_ENTRY_R6_LOWER	7
-#define NUM_BOOT_ENTRY		8
-#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
+struct epapr_spin_table {
+	u32	addr_h;
+	u32	addr_l;
+	u32	r3_h;
+	u32	r3_l;
+	u32	reserved;
+	u32	pir;
+};
 
 #ifdef CONFIG_85xx_TB_SYNC
 static struct ccsr_guts __iomem *guts;
@@ -106,15 +103,45 @@ static void mpc85xx_take_timebase(void)
 }
 #endif
 
-static int __init
-smp_85xx_kick_cpu(int nr)
+#ifdef CONFIG_HOTPLUG_CPU
+static void __cpuinit smp_85xx_mach_cpu_die(void)
+{
+	unsigned int cpu = smp_processor_id();
+	u32 tmp;
+
+	local_irq_disable();
+	idle_task_exit();
+	generic_set_cpu_dead(cpu);
+	mb();
+
+	mtspr(SPRN_TCR, 0);
+
+	__flush_disable_L1();
+	tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
+	mtspr(SPRN_HID0, tmp);
+	isync();
+
+	/* Enter NAP mode. */
+	tmp = mfmsr();
+	tmp |= MSR_WE;
+	mb();
+	mtmsr(tmp);
+	isync();
+
+	while (1)
+		;
+}
+#endif
+
+static int __cpuinit smp_85xx_kick_cpu(int nr)
 {
 	unsigned long flags;
 	const u64 *cpu_rel_addr;
-	__iomem u32 *bptr_vaddr;
+	__iomem struct epapr_spin_table *spin_table;
 	struct device_node *np;
-	int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
+	int hw_cpu = get_hard_smp_processor_id(nr);
 	int ioremappable;
+	int ret = 0;
 
 	WARN_ON(nr < 0 || nr >= NR_CPUS);
 	WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
@@ -139,46 +166,80 @@ smp_85xx_kick_cpu(int nr)
 
 	/* Map the spin table */
 	if (ioremappable)
-		bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+		spin_table = ioremap(*cpu_rel_addr,
+				sizeof(struct epapr_spin_table));
 	else
-		bptr_vaddr = phys_to_virt(*cpu_rel_addr);
+		spin_table = phys_to_virt(*cpu_rel_addr);
 
 	local_irq_save(flags);
-
-	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
 #ifdef CONFIG_PPC32
-	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
+#ifdef CONFIG_HOTPLUG_CPU
+	/* Corresponding to generic_set_cpu_dead() */
+	generic_set_cpu_up(nr);
+
+	if (system_state == SYSTEM_RUNNING) {
+		out_be32(&spin_table->addr_l, 0);
+
+		/*
+		 * We don't set the BPTR register here since it already points
+		 * to the boot page properly.
+		 */
+		mpic_reset_core(hw_cpu);
+
+		/* wait until core is ready... */
+		if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
+						10000, 100)) {
+			pr_err("%s: timeout waiting for core %d to reset\n",
+							__func__, hw_cpu);
+			ret = -ENOENT;
+			goto out;
+		}
+
+		/*  clear the acknowledge status */
+		__secondary_hold_acknowledge = -1;
+	}
+#endif
+	out_be32(&spin_table->pir, hw_cpu);
+	out_be32(&spin_table->addr_l, __pa(__early_start));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 
 	/* Wait a bit for the CPU to ack. */
-	while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
-		mdelay(1);
+	if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
+					10000, 100)) {
+		pr_err("%s: timeout waiting for core %d to ack\n",
+						__func__, hw_cpu);
+		ret = -ENOENT;
+		goto out;
+	}
+out:
 #else
 	smp_generic_kick_cpu(nr);
 
-	out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
-		__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+	out_be32(&spin_table->pir, hw_cpu);
+	out_be64((u64 *)(&spin_table->addr_h),
+	  __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 #endif
-
 	local_irq_restore(flags);
 
 	if (ioremappable)
-		iounmap(bptr_vaddr);
+		iounmap(spin_table);
 
-	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
-
-	return 0;
+	return ret;
 }
 
 struct smp_ops_t smp_85xx_ops = {
 	.kick_cpu = smp_85xx_kick_cpu,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_disable	= generic_cpu_disable,
+	.cpu_die	= generic_cpu_die,
+#endif
 #ifdef CONFIG_KEXEC
 	.give_timebase	= smp_generic_give_timebase,
 	.take_timebase	= smp_generic_take_timebase,
@@ -282,8 +343,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
 }
 #endif /* CONFIG_KEXEC */
 
-static void __init
-smp_85xx_setup_cpu(int cpu_nr)
+static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
 {
 	if (smp_85xx_ops.probe == smp_mpic_probe)
 		mpic_setup_this_cpu();
@@ -330,6 +390,9 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
 		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
 #endif
+#ifdef CONFIG_HOTPLUG_CPU
+		ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
 		of_node_put(np);
 	}
 
-- 
1.6.4.1



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

* [PATCH v6 2/5] powerpc/85xx: add HOTPLUG_CPU support
@ 2012-06-26 10:25   ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel

From: Li Yang <leoli@freescale.com>

Add support to disable and re-enable individual cores at runtime
on MPC85xx/QorIQ SMP machines. Currently support e500v1/e500v2 core.

MPC85xx machines use ePAPR spin-table in boot page for CPU kick-off.
This patch uses the boot page from bootloader to boot core at runtime.
It supports 32-bit and 36-bit physical address.

Add generic_set_cpu_up() to set cpu_state as CPU_UP_PREPARE in kick_cpu().

Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
Changes for v6:
 * do not guard __flush_disable_L1() by ifdefs
 * added isync() after mtspr()

 arch/powerpc/Kconfig                  |    6 +-
 arch/powerpc/include/asm/cacheflush.h |    2 +
 arch/powerpc/include/asm/smp.h        |    2 +
 arch/powerpc/kernel/head_fsl_booke.S  |   28 +++++++
 arch/powerpc/kernel/smp.c             |   10 +++
 arch/powerpc/platforms/85xx/Kconfig   |    2 +-
 arch/powerpc/platforms/85xx/smp.c     |  137 ++++++++++++++++++++++++---------
 7 files changed, 147 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 38786c8..d6bacbe 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -220,7 +220,8 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
 	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-		   (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x
+		   (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+		   || 44x || 40x
 
 config PPC_DCR_NATIVE
 	bool
@@ -331,7 +332,8 @@ config SWIOTLB
 
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
-	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
+	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
+	PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
 	---help---
 	  Say Y here to be able to disable and re-enable individual
 	  CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ab9e402..b843e35 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,6 +30,8 @@ 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);
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ebc24dc..e807e9d 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -65,6 +65,7 @@ int generic_cpu_disable(void);
 void generic_cpu_die(unsigned int cpu);
 void generic_mach_cpu_die(void);
 void generic_set_cpu_dead(unsigned int cpu);
+void generic_set_cpu_up(unsigned int cpu);
 int generic_check_cpu_restart(unsigned int cpu);
 #endif
 
@@ -190,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
+extern void __early_start(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index de80e0f..be0261b 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -996,6 +996,34 @@ _GLOBAL(flush_dcache_L1)
 
 	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/kernel/smp.c b/arch/powerpc/kernel/smp.c
index d9f9441..e0ffe03 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -423,6 +423,16 @@ void generic_set_cpu_dead(unsigned int cpu)
 	per_cpu(cpu_state, cpu) = CPU_DEAD;
 }
 
+/*
+ * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise
+ * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(),
+ * which makes the delay in generic_cpu_die() not happen.
+ */
+void generic_set_cpu_up(unsigned int cpu)
+{
+	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+}
+
 int generic_check_cpu_restart(unsigned int cpu)
 {
 	return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE;
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 8dd7147..e4beb34 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -8,7 +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 85xx_TB_SYNC if KEXEC
+	select 85xx_TB_SYNC if KEXEC || HOTPLUG_CPU
 	default y
 
 if FSL_SOC_BOOKE
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index edb0cad..2854bfa 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -2,7 +2,7 @@
  * Author: Andy Fleming <afleming@freescale.com>
  * 	   Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2006-2008, 2011 Freescale Semiconductor Inc.
+ * Copyright 2006-2008, 2011-2012 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
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/kexec.h>
 #include <linux/highmem.h>
+#include <linux/cpu.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -30,18 +31,14 @@
 #include <sysdev/mpic.h>
 #include "smp.h"
 
-extern void __early_start(void);
-
-#define BOOT_ENTRY_ADDR_UPPER	0
-#define BOOT_ENTRY_ADDR_LOWER	1
-#define BOOT_ENTRY_R3_UPPER	2
-#define BOOT_ENTRY_R3_LOWER	3
-#define BOOT_ENTRY_RESV		4
-#define BOOT_ENTRY_PIR		5
-#define BOOT_ENTRY_R6_UPPER	6
-#define BOOT_ENTRY_R6_LOWER	7
-#define NUM_BOOT_ENTRY		8
-#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
+struct epapr_spin_table {
+	u32	addr_h;
+	u32	addr_l;
+	u32	r3_h;
+	u32	r3_l;
+	u32	reserved;
+	u32	pir;
+};
 
 #ifdef CONFIG_85xx_TB_SYNC
 static struct ccsr_guts __iomem *guts;
@@ -106,15 +103,45 @@ static void mpc85xx_take_timebase(void)
 }
 #endif
 
-static int __init
-smp_85xx_kick_cpu(int nr)
+#ifdef CONFIG_HOTPLUG_CPU
+static void __cpuinit smp_85xx_mach_cpu_die(void)
+{
+	unsigned int cpu = smp_processor_id();
+	u32 tmp;
+
+	local_irq_disable();
+	idle_task_exit();
+	generic_set_cpu_dead(cpu);
+	mb();
+
+	mtspr(SPRN_TCR, 0);
+
+	__flush_disable_L1();
+	tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
+	mtspr(SPRN_HID0, tmp);
+	isync();
+
+	/* Enter NAP mode. */
+	tmp = mfmsr();
+	tmp |= MSR_WE;
+	mb();
+	mtmsr(tmp);
+	isync();
+
+	while (1)
+		;
+}
+#endif
+
+static int __cpuinit smp_85xx_kick_cpu(int nr)
 {
 	unsigned long flags;
 	const u64 *cpu_rel_addr;
-	__iomem u32 *bptr_vaddr;
+	__iomem struct epapr_spin_table *spin_table;
 	struct device_node *np;
-	int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
+	int hw_cpu = get_hard_smp_processor_id(nr);
 	int ioremappable;
+	int ret = 0;
 
 	WARN_ON(nr < 0 || nr >= NR_CPUS);
 	WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
@@ -139,46 +166,80 @@ smp_85xx_kick_cpu(int nr)
 
 	/* Map the spin table */
 	if (ioremappable)
-		bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+		spin_table = ioremap(*cpu_rel_addr,
+				sizeof(struct epapr_spin_table));
 	else
-		bptr_vaddr = phys_to_virt(*cpu_rel_addr);
+		spin_table = phys_to_virt(*cpu_rel_addr);
 
 	local_irq_save(flags);
-
-	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
 #ifdef CONFIG_PPC32
-	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
+#ifdef CONFIG_HOTPLUG_CPU
+	/* Corresponding to generic_set_cpu_dead() */
+	generic_set_cpu_up(nr);
+
+	if (system_state == SYSTEM_RUNNING) {
+		out_be32(&spin_table->addr_l, 0);
+
+		/*
+		 * We don't set the BPTR register here since it already points
+		 * to the boot page properly.
+		 */
+		mpic_reset_core(hw_cpu);
+
+		/* wait until core is ready... */
+		if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
+						10000, 100)) {
+			pr_err("%s: timeout waiting for core %d to reset\n",
+							__func__, hw_cpu);
+			ret = -ENOENT;
+			goto out;
+		}
+
+		/*  clear the acknowledge status */
+		__secondary_hold_acknowledge = -1;
+	}
+#endif
+	out_be32(&spin_table->pir, hw_cpu);
+	out_be32(&spin_table->addr_l, __pa(__early_start));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 
 	/* Wait a bit for the CPU to ack. */
-	while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
-		mdelay(1);
+	if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
+					10000, 100)) {
+		pr_err("%s: timeout waiting for core %d to ack\n",
+						__func__, hw_cpu);
+		ret = -ENOENT;
+		goto out;
+	}
+out:
 #else
 	smp_generic_kick_cpu(nr);
 
-	out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
-		__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+	out_be32(&spin_table->pir, hw_cpu);
+	out_be64((u64 *)(&spin_table->addr_h),
+	  __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 #endif
-
 	local_irq_restore(flags);
 
 	if (ioremappable)
-		iounmap(bptr_vaddr);
+		iounmap(spin_table);
 
-	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
-
-	return 0;
+	return ret;
 }
 
 struct smp_ops_t smp_85xx_ops = {
 	.kick_cpu = smp_85xx_kick_cpu,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_disable	= generic_cpu_disable,
+	.cpu_die	= generic_cpu_die,
+#endif
 #ifdef CONFIG_KEXEC
 	.give_timebase	= smp_generic_give_timebase,
 	.take_timebase	= smp_generic_take_timebase,
@@ -282,8 +343,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
 }
 #endif /* CONFIG_KEXEC */
 
-static void __init
-smp_85xx_setup_cpu(int cpu_nr)
+static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
 {
 	if (smp_85xx_ops.probe == smp_mpic_probe)
 		mpic_setup_this_cpu();
@@ -330,6 +390,9 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
 		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
 #endif
+#ifdef CONFIG_HOTPLUG_CPU
+		ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
 		of_node_put(np);
 	}
 
-- 
1.6.4.1

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

* [PATCH v6 3/5] powerpc/85xx: add sleep and deep sleep support
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-26 10:25   ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel, galak, leoli

From: Li Yang <leoli@freescale.com>

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

Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode
in addtion to the sleep PM mode.

While in deep sleep PM mode, additionally, the power supply is
removed from e500 core and most IP blocks. Only the blocks needed
to wake up the chip out of deep sleep are ON.

This patch supports 32-bit and 36-bit address space.

The sleep mode is equal to the Standby state in Linux. The deep sleep
mode is equal to the Suspend-to-RAM state of Linux Power Management.

Command to enter sleep mode.
  echo standby > /sys/power/state
Command to enter deep sleep mode.
  echo mem > /sys/power/state

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
Changes for v6:
 * changed the declaration of flush_dcache_L1()
 * some minor changes

 arch/powerpc/Kconfig                  |    2 +-
 arch/powerpc/include/asm/cacheflush.h |    2 +
 arch/powerpc/kernel/Makefile          |    3 +
 arch/powerpc/kernel/l2cache_85xx.S    |   53 +++
 arch/powerpc/platforms/85xx/Makefile  |    2 +-
 arch/powerpc/platforms/85xx/sleep.S   |  609 +++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_pmc.c         |   98 +++++-
 arch/powerpc/sysdev/fsl_soc.h         |    5 +
 8 files changed, 754 insertions(+), 20 deletions(-)
 create mode 100644 arch/powerpc/kernel/l2cache_85xx.S
 create mode 100644 arch/powerpc/platforms/85xx/sleep.S

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d6bacbe..6883769 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -673,7 +673,7 @@ config FSL_PCI
 config FSL_PMC
 	bool
 	default y
-	depends on SUSPEND && (PPC_85xx || PPC_86xx)
+	depends on SUSPEND && (PPC_85xx || PPC_86xx) && !PPC_E500MC
 	help
 	  Freescale MPC85xx/MPC86xx power management controller support
 	  (suspend/resume). For MPC83xx see platforms/83xx/suspend.c
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index b843e35..6c5f1c2 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -58,6 +58,8 @@ extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
 extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
 #endif
 
+extern void flush_dcache_L1(void);
+
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 	do { \
 		memcpy(dst, src, len); \
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index f5808a3..cb70dba 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP)		+= fadump.o
 ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)		+= idle_e500.o
 endif
+ifneq ($(CONFIG_PPC_E500MC),y)
+obj-$(CONFIG_PPC_85xx)		+= l2cache_85xx.o
+endif
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o
diff --git a/arch/powerpc/kernel/l2cache_85xx.S b/arch/powerpc/kernel/l2cache_85xx.S
new file mode 100644
index 0000000..b0b7d1c
--- /dev/null
+++ b/arch/powerpc/kernel/l2cache_85xx.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *	Scott Wood <scottwood@freescale.com>
+ *	Dave Liu <daveliu@freescale.com>
+ * implement the L2 cache operations of e500 based L2 controller
+ *
+ * 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/reg.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+	.section .text
+
+	/* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(flush_disable_L2)
+	/* It's a write-through cache, so only invalidation is needed. */
+	mbar
+	isync
+	lwz	r4, 0(r3)
+	li	r5, 1
+	rlwimi	r4, r5, 30, 0xc0000000
+	stw	r4, 0(r3)
+
+	/* Wait for the invalidate to finish */
+1:	lwz	r4, 0(r3)
+	andis.	r4, r4, 0x4000
+	bne	1b
+	mbar
+
+	blr
+
+	/* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(invalidate_enable_L2)
+	mbar
+	isync
+	lwz	r4, 0(r3)
+	li	r5, 3
+	rlwimi	r4, r5, 30, 0xc0000000
+	stw	r4, 0(r3)
+
+	/* Wait for the invalidate to finish */
+1:	lwz	r4, 0(r3)
+	andis.	r4, r4, 0x4000
+	bne	1b
+	mbar
+
+	blr
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 2125d4c..d154e39 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_SMP) += smp.o
 
-obj-y += common.o
+obj-y += common.o sleep.o
 
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..b272f0c
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,609 @@
+/*
+ * Enter and leave deep sleep/sleep state on MPC85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (C) 2006-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+
+#define SS_TB		0x00
+#define SS_HID		0x08 /* 2 HIDs */
+#define SS_IAC		0x10 /* 2 IACs */
+#define SS_DAC		0x18 /* 2 DACs */
+#define SS_DBCR		0x20 /* 3 DBCRs */
+#define SS_PID		0x2c /* 3 PIDs */
+#define SS_SPRG		0x38 /* 8 SPRGs */
+#define SS_IVOR		0x58 /* 20 interrupt vectors */
+#define SS_TCR		0xa8
+#define SS_BUCSR	0xac
+#define SS_L1CSR	0xb0 /* 2 L1CSRs */
+#define SS_MSR		0xb8
+#define SS_USPRG	0xbc
+#define SS_GPREG	0xc0 /* r12-r31 */
+#define SS_LR		0x110
+#define SS_CR		0x114
+#define SS_SP		0x118
+#define SS_CURRENT	0x11c
+#define SS_IVPR		0x120
+#define SS_BPTR		0x124
+
+
+#define STATE_SAVE_SIZE 0x128
+
+	.section .data
+	.align	5
+mpc85xx_sleep_save_area:
+	.space	STATE_SAVE_SIZE
+ccsrbase_low:
+	.long	0
+ccsrbase_high:
+	.long	0
+powmgtreq:
+	.long	0
+
+	.section .text
+	.align	12
+
+	/*
+	 * r3 = high word of physical address of CCSR
+	 * r4 = low word of physical address of CCSR
+	 * r5 = JOG or deep sleep request
+	 *      JOG-0x00200000, deep sleep-0x00100000
+	 */
+_GLOBAL(mpc85xx_enter_deep_sleep)
+	lis	r6, ccsrbase_low@ha
+	stw	r4, ccsrbase_low@l(r6)
+	lis	r6, ccsrbase_high@ha
+	stw	r3, ccsrbase_high@l(r6)
+
+	lis	r6, powmgtreq@ha
+	stw	r5, powmgtreq@l(r6)
+
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	mfspr	r5, SPRN_HID0
+	mfspr	r6, SPRN_HID1
+
+	stw	r5, SS_HID+0(r10)
+	stw	r6, SS_HID+4(r10)
+
+	mfspr	r4, SPRN_IAC1
+	mfspr	r5, SPRN_IAC2
+	mfspr	r6, SPRN_DAC1
+	mfspr	r7, SPRN_DAC2
+
+	stw	r4, SS_IAC+0(r10)
+	stw	r5, SS_IAC+4(r10)
+	stw	r6, SS_DAC+0(r10)
+	stw	r7, SS_DAC+4(r10)
+
+	mfspr	r4, SPRN_DBCR0
+	mfspr	r5, SPRN_DBCR1
+	mfspr	r6, SPRN_DBCR2
+
+	stw	r4, SS_DBCR+0(r10)
+	stw	r5, SS_DBCR+4(r10)
+	stw	r6, SS_DBCR+8(r10)
+
+	mfspr	r4, SPRN_PID0
+	mfspr	r5, SPRN_PID1
+	mfspr	r6, SPRN_PID2
+
+	stw	r4, SS_PID+0(r10)
+	stw	r5, SS_PID+4(r10)
+	stw	r6, SS_PID+8(r10)
+
+	mfspr	r4, SPRN_SPRG0
+	mfspr	r5, SPRN_SPRG1
+	mfspr	r6, SPRN_SPRG2
+	mfspr	r7, SPRN_SPRG3
+
+	stw	r4, SS_SPRG+0x00(r10)
+	stw	r5, SS_SPRG+0x04(r10)
+	stw	r6, SS_SPRG+0x08(r10)
+	stw	r7, SS_SPRG+0x0c(r10)
+
+	mfspr	r4, SPRN_SPRG4
+	mfspr	r5, SPRN_SPRG5
+	mfspr	r6, SPRN_SPRG6
+	mfspr	r7, SPRN_SPRG7
+
+	stw	r4, SS_SPRG+0x10(r10)
+	stw	r5, SS_SPRG+0x14(r10)
+	stw	r6, SS_SPRG+0x18(r10)
+	stw	r7, SS_SPRG+0x1c(r10)
+
+	mfspr	r4, SPRN_IVPR
+	stw	r4, SS_IVPR(r10)
+
+	mfspr	r4, SPRN_IVOR0
+	mfspr	r5, SPRN_IVOR1
+	mfspr	r6, SPRN_IVOR2
+	mfspr	r7, SPRN_IVOR3
+
+	stw	r4, SS_IVOR+0x00(r10)
+	stw	r5, SS_IVOR+0x04(r10)
+	stw	r6, SS_IVOR+0x08(r10)
+	stw	r7, SS_IVOR+0x0c(r10)
+
+	mfspr	r4, SPRN_IVOR4
+	mfspr	r5, SPRN_IVOR5
+	mfspr	r6, SPRN_IVOR6
+	mfspr	r7, SPRN_IVOR7
+
+	stw	r4, SS_IVOR+0x10(r10)
+	stw	r5, SS_IVOR+0x14(r10)
+	stw	r6, SS_IVOR+0x18(r10)
+	stw	r7, SS_IVOR+0x1c(r10)
+
+	mfspr	r4, SPRN_IVOR8
+	mfspr	r5, SPRN_IVOR9
+	mfspr	r6, SPRN_IVOR10
+	mfspr	r7, SPRN_IVOR11
+
+	stw	r4, SS_IVOR+0x20(r10)
+	stw	r5, SS_IVOR+0x24(r10)
+	stw	r6, SS_IVOR+0x28(r10)
+	stw	r7, SS_IVOR+0x2c(r10)
+
+	mfspr	r4, SPRN_IVOR12
+	mfspr	r5, SPRN_IVOR13
+	mfspr	r6, SPRN_IVOR14
+	mfspr	r7, SPRN_IVOR15
+
+	stw	r4, SS_IVOR+0x30(r10)
+	stw	r5, SS_IVOR+0x34(r10)
+	stw	r6, SS_IVOR+0x38(r10)
+	stw	r7, SS_IVOR+0x3c(r10)
+
+	mfspr	r4, SPRN_IVOR32
+	mfspr	r5, SPRN_IVOR33
+	mfspr	r6, SPRN_IVOR34
+	mfspr	r7, SPRN_IVOR35
+
+	stw	r4, SS_IVOR+0x40(r10)
+	stw	r5, SS_IVOR+0x44(r10)
+	stw	r6, SS_IVOR+0x48(r10)
+	stw	r7, SS_IVOR+0x4c(r10)
+
+	mfspr	r4, SPRN_TCR
+	mfspr	r5, SPRN_BUCSR
+	mfspr	r6, SPRN_L1CSR0
+	mfspr	r7, SPRN_L1CSR1
+	mfspr	r8, SPRN_USPRG0
+
+	stw	r4, SS_TCR(r10)
+	stw	r5, SS_BUCSR(r10)
+	stw	r6, SS_L1CSR+0(r10)
+	stw	r7, SS_L1CSR+4(r10)
+	stw	r8, SS_USPRG+0(r10)
+
+	stmw	r12, SS_GPREG(r10)
+
+	mfmsr	r4
+	mflr	r5
+	mfcr	r6
+
+	stw	r4, SS_MSR(r10)
+	stw	r5, SS_LR(r10)
+	stw	r6, SS_CR(r10)
+	stw	r1, SS_SP(r10)
+	stw	r2, SS_CURRENT(r10)
+
+1:	mftbu	r4
+	mftb	r5
+	mftbu	r6
+	cmpw	r4, r6
+	bne	1b
+
+	stw	r4, SS_TB+0(r10)
+	stw	r5, SS_TB+4(r10)
+
+	lis	r5, ccsrbase_low@ha
+	lwz	r4, ccsrbase_low@l(r5)
+	lis	r5, ccsrbase_high@ha
+	lwz	r3, ccsrbase_high@l(r5)
+
+	/* Disable machine checks and critical exceptions */
+	mfmsr	r5
+	rlwinm	r5, r5, 0, ~MSR_CE
+	rlwinm	r5, r5, 0, ~MSR_ME
+	mtmsr	r5
+	isync
+
+	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
+	lis	r5, 0x100f
+	mtspr	SPRN_MAS0, r5
+	lis	r5, 0xc000
+	ori	r5, r5, 0x0500
+	mtspr	SPRN_MAS1, r5
+	lis	r5, 0xf000
+	ori	r5, r5, 0x000a
+	mtspr	SPRN_MAS2, r5
+	rlwinm	r5, r4, 0, 0xfffff000
+	ori	r5, r5, 0x0005
+	mtspr	SPRN_MAS3, r5
+	mtspr	SPRN_MAS7, r3
+	isync
+	tlbwe
+	isync
+
+	lis	r3, 0xf000
+	lwz	r4, 0x20(r3)
+	stw	r4, SS_BPTR(r10)
+
+	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 */
+	bl	flush_disable_L2
+	bl	__flush_disable_L1
+
+	/* Enable I-cache, so as not to upset the bus
+	 * with our loop.
+	 */
+
+	mfspr	r4, SPRN_L1CSR1
+	ori	r4, r4, 1
+	mtspr	SPRN_L1CSR1, r4
+	isync
+
+	/* Set boot page translation */
+	lis	r3, 0xf000
+	lis	r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
+	ori	r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
+	rlwinm	r4, r4, 20, 0x000fffff
+	oris	r4, r4, 0x8000
+	stw	r4, 0x20(r3)
+	lwz	r4, 0x20(r3)		/* read-back to flush write */
+	twi	0, r4, 0
+	isync
+
+	/* Disable the decrementer */
+	mfspr	r4, SPRN_TCR
+	rlwinm	r4, r4, 0, ~TCR_DIE
+	mtspr	SPRN_TCR, r4
+
+	mfspr	r4, SPRN_TSR
+	oris	r4, r4, TSR_DIS@h
+	mtspr	SPRN_TSR, r4
+
+	/* set PMRCCR[VRCNT] to wait power stable for 40ms */
+	lis	r3, 0xf00e
+	lwz	r4, 0x84(r3)
+	clrlwi	r4, r4, 16
+	oris	r4, r4, 0x12a3
+	stw	r4, 0x84(r3)
+	lwz	r4, 0x84(r3)
+
+	/* set deep sleep bit in POWMGTSCR */
+	lis	r3, powmgtreq@ha
+	lwz	r8, powmgtreq@l(r3)
+
+	lis	r3, 0xf00e
+	lwz	r4, 0x80(r3)
+	or	r4, r4, r8
+	stw	r4, 0x80(r3)
+	lwz	r4, 0x80(r3)		/* read-back to flush write */
+	twi	0, r4, 0
+	isync
+
+	mftb	r5
+1:	/* spin until either we enter deep sleep, or the sleep process is
+	 * aborted due to a pending wakeup event.  Wait some time between
+	 * accesses, so we don't flood the bus and prevent the pmc from
+	 * detecting an idle system.
+	 */
+
+	mftb	r4
+	subf	r7, r5, r4
+	cmpwi	r7, 1000
+	blt	1b
+	mr	r5, r4
+
+	lwz	r6, 0x80(r3)
+	andis.	r6, r6, 0x0010
+	bne	1b
+	b	2f
+
+2:	mfspr	r4, SPRN_PIR
+	andi.	r4, r4, 1
+99:	bne	99b
+
+	/* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
+	lis	r4, 0x1001
+	mtspr	SPRN_MAS0, r4
+	lis	r4, 0xc000
+	ori	r4, r4, 0x0800
+	mtspr	SPRN_MAS1, r4
+	li	r4, 0
+	mtspr	SPRN_MAS2, r4
+	li	r4, 0x0015
+	mtspr	SPRN_MAS3, r4
+	li	r4, 0
+	mtspr	SPRN_MAS7, r4
+	isync
+	tlbwe
+	isync
+
+	lis	r3, (3f - PAGE_OFFSET)@h
+	ori	r3, r3, (3f - PAGE_OFFSET)@l
+	mtctr	r3
+	bctr
+
+	/* Locate the resume vector in the last word of the current page. */
+	. = mpc85xx_enter_deep_sleep + 0xffc
+mpc85xx_deep_resume:
+	b	2b
+
+3:
+	/* Restore the contents of TLB1[0].  It is assumed that it covers
+	 * the currently executing code and the sleep save area, and that
+	 * it does not alias our temporary mapping (which is at virtual zero).
+	 */
+	lis	r3, (TLBCAM - PAGE_OFFSET)@h
+	ori	r3, r3, (TLBCAM - PAGE_OFFSET)@l
+
+	lwz	r4, 0(r3)
+	lwz	r5, 4(r3)
+	lwz	r6, 8(r3)
+	lwz	r7, 12(r3)
+	lwz	r8, 16(r3)
+
+	mtspr	SPRN_MAS0, r4
+	mtspr	SPRN_MAS1, r5
+	mtspr	SPRN_MAS2, r6
+	mtspr	SPRN_MAS3, r7
+	mtspr	SPRN_MAS7, r8
+
+	isync
+	tlbwe
+	isync
+
+	/* Access the ccsrbase address with TLB1[0] */
+	lis	r5, ccsrbase_low@ha
+	lwz	r4, ccsrbase_low@l(r5)
+	lis	r5, ccsrbase_high@ha
+	lwz	r3, ccsrbase_high@l(r5)
+
+	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
+	lis	r5, 0x100f
+	mtspr	SPRN_MAS0, r5
+	lis	r5, 0xc000
+	ori	r5, r5, 0x0500
+	mtspr	SPRN_MAS1, r5
+	lis	r5, 0xf000
+	ori	r5, r5, 0x000a
+	mtspr	SPRN_MAS2, r5
+	rlwinm	r5, r4, 0, 0xfffff000
+	ori	r5, r5, 0x0005
+	mtspr	SPRN_MAS3, r5
+	mtspr	SPRN_MAS7, r3
+	isync
+	tlbwe
+	isync
+
+	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 */
+	bl	invalidate_enable_L2
+
+	/* Access the MEM(r10) with TLB1[0] */
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	lis	r3, 0xf000
+	lwz	r4, SS_BPTR(r10)
+	stw	r4, 0x20(r3)		/* restore BPTR */
+
+	/* Program shift running space to PAGE_OFFSET */
+	mfmsr	r3
+	lis	r4, 1f@h
+	ori	r4, r4, 1f@l
+
+	mtsrr1	r3
+	mtsrr0	r4
+	rfi
+
+1:	/* Restore the rest of TLB1, in ascending order so that
+	 * the TLB1[1] gets invalidated first.
+	 *
+	 * XXX: It's better to invalidate the temporary mapping
+	 * TLB1[15] for CCSR before restore any TLB1 entry include 0.
+	 */
+	lis	r4, 0x100f
+	mtspr	SPRN_MAS0, r4
+	lis	r4, 0
+	mtspr	SPRN_MAS1, r4
+	isync
+	tlbwe
+	isync
+
+	lis	r3, (TLBCAM + 5*4 - 4)@h
+	ori	r3, r3, (TLBCAM + 5*4 - 4)@l
+	li	r4, 15
+	mtctr	r4
+
+2:
+	lwz	r5, 4(r3)
+	lwz	r6, 8(r3)
+	lwz	r7, 12(r3)
+	lwz	r8, 16(r3)
+	lwzu	r9, 20(r3)
+
+	mtspr	SPRN_MAS0, r5
+	mtspr	SPRN_MAS1, r6
+	mtspr	SPRN_MAS2, r7
+	mtspr	SPRN_MAS3, r8
+	mtspr	SPRN_MAS7, r9
+
+	isync
+	tlbwe
+	isync
+	bdnz	2b
+
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	lwz	r5, SS_HID+0(r10)
+	lwz	r6, SS_HID+4(r10)
+
+	isync
+	mtspr	SPRN_HID0, r5
+	isync
+
+	msync
+	mtspr	SPRN_HID1, r6
+	isync
+
+	lwz	r4, SS_IAC+0(r10)
+	lwz	r5, SS_IAC+4(r10)
+	lwz	r6, SS_DAC+0(r10)
+	lwz	r7, SS_DAC+4(r10)
+
+	mtspr	SPRN_IAC1, r4
+	mtspr	SPRN_IAC2, r5
+	mtspr	SPRN_DAC1, r6
+	mtspr	SPRN_DAC2, r7
+
+	lwz	r4, SS_DBCR+0(r10)
+	lwz	r5, SS_DBCR+4(r10)
+	lwz	r6, SS_DBCR+8(r10)
+
+	mtspr	SPRN_DBCR0, r4
+	mtspr	SPRN_DBCR1, r5
+	mtspr	SPRN_DBCR2, r6
+
+	lwz	r4, SS_PID+0(r10)
+	lwz	r5, SS_PID+4(r10)
+	lwz	r6, SS_PID+8(r10)
+
+	mtspr	SPRN_PID0, r4
+	mtspr	SPRN_PID1, r5
+	mtspr	SPRN_PID2, r6
+
+	lwz	r4, SS_SPRG+0x00(r10)
+	lwz	r5, SS_SPRG+0x04(r10)
+	lwz	r6, SS_SPRG+0x08(r10)
+	lwz	r7, SS_SPRG+0x0c(r10)
+
+	mtspr	SPRN_SPRG0, r4
+	mtspr	SPRN_SPRG1, r5
+	mtspr	SPRN_SPRG2, r6
+	mtspr	SPRN_SPRG3, r7
+
+	lwz	r4, SS_SPRG+0x10(r10)
+	lwz	r5, SS_SPRG+0x14(r10)
+	lwz	r6, SS_SPRG+0x18(r10)
+	lwz	r7, SS_SPRG+0x1c(r10)
+
+	mtspr	SPRN_SPRG4, r4
+	mtspr	SPRN_SPRG5, r5
+	mtspr	SPRN_SPRG6, r6
+	mtspr	SPRN_SPRG7, r7
+
+	lwz	r4, SS_IVPR(r10)
+	mtspr	SPRN_IVPR, r4
+
+	lwz	r4, SS_IVOR+0x00(r10)
+	lwz	r5, SS_IVOR+0x04(r10)
+	lwz	r6, SS_IVOR+0x08(r10)
+	lwz	r7, SS_IVOR+0x0c(r10)
+
+	mtspr	SPRN_IVOR0, r4
+	mtspr	SPRN_IVOR1, r5
+	mtspr	SPRN_IVOR2, r6
+	mtspr	SPRN_IVOR3, r7
+
+	lwz	r4, SS_IVOR+0x10(r10)
+	lwz	r5, SS_IVOR+0x14(r10)
+	lwz	r6, SS_IVOR+0x18(r10)
+	lwz	r7, SS_IVOR+0x1c(r10)
+
+	mtspr	SPRN_IVOR4, r4
+	mtspr	SPRN_IVOR5, r5
+	mtspr	SPRN_IVOR6, r6
+	mtspr	SPRN_IVOR7, r7
+
+	lwz	r4, SS_IVOR+0x20(r10)
+	lwz	r5, SS_IVOR+0x24(r10)
+	lwz	r6, SS_IVOR+0x28(r10)
+	lwz	r7, SS_IVOR+0x2c(r10)
+
+	mtspr	SPRN_IVOR8, r4
+	mtspr	SPRN_IVOR9, r5
+	mtspr	SPRN_IVOR10, r6
+	mtspr	SPRN_IVOR11, r7
+
+	lwz	r4, SS_IVOR+0x30(r10)
+	lwz	r5, SS_IVOR+0x34(r10)
+	lwz	r6, SS_IVOR+0x38(r10)
+	lwz	r7, SS_IVOR+0x3c(r10)
+
+	mtspr	SPRN_IVOR12, r4
+	mtspr	SPRN_IVOR13, r5
+	mtspr	SPRN_IVOR14, r6
+	mtspr	SPRN_IVOR15, r7
+
+	lwz	r4, SS_IVOR+0x40(r10)
+	lwz	r5, SS_IVOR+0x44(r10)
+	lwz	r6, SS_IVOR+0x48(r10)
+	lwz	r7, SS_IVOR+0x4c(r10)
+
+	mtspr	SPRN_IVOR32, r4
+	mtspr	SPRN_IVOR33, r5
+	mtspr	SPRN_IVOR34, r6
+	mtspr	SPRN_IVOR35, r7
+
+	lwz	r4, SS_TCR(r10)
+	lwz	r5, SS_BUCSR(r10)
+	lwz	r6, SS_L1CSR+0(r10)
+	lwz	r7, SS_L1CSR+4(r10)
+	lwz	r8, SS_USPRG+0(r10)
+
+	mtspr	SPRN_TCR, r4
+	mtspr	SPRN_BUCSR, r5
+
+	msync
+	isync
+	mtspr	SPRN_L1CSR0, r6
+	isync
+
+	mtspr	SPRN_L1CSR1, r7
+	isync
+
+	mtspr	SPRN_USPRG0, r8
+
+	lmw	r12, SS_GPREG(r10)
+
+	lwz	r1, SS_SP(r10)
+	lwz	r2, SS_CURRENT(r10)
+	lwz	r4, SS_MSR(r10)
+	lwz	r5, SS_LR(r10)
+	lwz	r6, SS_CR(r10)
+
+	msync
+	mtmsr	r4
+	isync
+
+	mtlr	r5
+	mtcr	r6
+
+	li	r4, 0
+	mtspr	SPRN_TBWL, r4
+
+	lwz	r4, SS_TB+0(r10)
+	lwz	r5, SS_TB+4(r10)
+
+	mtspr	SPRN_TBWU, r4
+	mtspr	SPRN_TBWL, r5
+
+	lis	r3, 1
+	mtdec	r3
+
+	blr
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 592a0f8..45718c5 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -2,6 +2,7 @@
  * Suspend/resume support
  *
  * Copyright 2009  MontaVista Software, Inc.
+ * Copyright 2010-2012 Freescale Semiconductor Inc.
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
  *
@@ -19,39 +20,89 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/of_platform.h>
+#include <linux/pm.h>
+#include <asm/cacheflush.h>
+#include <asm/switch_to.h>
+
+#include <sysdev/fsl_soc.h>
 
 struct pmc_regs {
+	/* 0xe0070: Device disable control register */
 	__be32 devdisr;
+	/* 0xe0074: 2nd Device disable control register */
 	__be32 devdisr2;
-	__be32 :32;
-	__be32 :32;
-	__be32 pmcsr;
-#define PMCSR_SLP	(1 << 17)
+	__be32 res1;
+	/* 0xe007c: Power Management Jog Control Register */
+	__be32 pmjcr;
+	/* 0xe0080: Power management control and status register */
+	__be32 powmgtcsr;
+#define POWMGTCSR_SLP		0x00020000
+#define POWMGTCSR_DPSLP		0x00100000
+	__be32 res3[2];
+	/* 0xe008c: Power management clock disable register */
+	__be32 pmcdr;
 };
 
-static struct device *pmc_dev;
 static struct pmc_regs __iomem *pmc_regs;
+static unsigned int pmc_flag;
+
+#define PMC_SLEEP	0x1
+#define PMC_DEEP_SLEEP	0x2
 
 static int pmc_suspend_enter(suspend_state_t state)
 {
-	int ret;
+	int ret = 0;
+
+	switch (state) {
+#ifdef CONFIG_PPC_85xx
+	case PM_SUSPEND_MEM:
+#ifdef CONFIG_SPE
+		enable_kernel_spe();
+#endif
+		enable_kernel_fp();
+
+		pr_debug("%s: Entering deep sleep\n", __func__);
+
+		local_irq_disable();
+		mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_DPSLP);
+
+		pr_debug("%s: Resumed from deep sleep\n", __func__);
+		break;
+#endif
 
-	setbits32(&pmc_regs->pmcsr, PMCSR_SLP);
-	/* At this point, the CPU is asleep. */
+	case PM_SUSPEND_STANDBY:
+		local_irq_disable();
+#ifdef CONFIG_PPC_85xx
+		flush_dcache_L1();
+#endif
+		setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);
+		/* At this point, the CPU is asleep. */
 
-	/* Upon resume, wait for SLP bit to be clear. */
-	ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0,
-				 10000, 10) ? 0 : -ETIMEDOUT;
-	if (ret)
-		dev_err(pmc_dev, "tired waiting for SLP bit to clear\n");
+		/* Upon resume, wait for SLP bit to be clear. */
+		ret = spin_event_timeout(
+			(in_be32(&pmc_regs->powmgtcsr) & POWMGTCSR_SLP) == 0,
+			10000, 10);
+		if (!ret) {
+			pr_err("%s: timeout waiting for SLP bit "
+				"to be cleared\n", __func__);
+			ret = -EINVAL;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+
+	}
 	return ret;
 }
 
 static int pmc_suspend_valid(suspend_state_t state)
 {
-	if (state != PM_SUSPEND_STANDBY)
+	if (((pmc_flag & PMC_SLEEP) && (state == PM_SUSPEND_STANDBY)) ||
+	    ((pmc_flag & PMC_DEEP_SLEEP) && (state == PM_SUSPEND_MEM)))
+		return 1;
+	else
 		return 0;
-	return 1;
 }
 
 static const struct platform_suspend_ops pmc_suspend_ops = {
@@ -59,14 +110,25 @@ static const struct platform_suspend_ops pmc_suspend_ops = {
 	.enter = pmc_suspend_enter,
 };
 
-static int pmc_probe(struct platform_device *ofdev)
+static int pmc_probe(struct platform_device *pdev)
 {
-	pmc_regs = of_iomap(ofdev->dev.of_node, 0);
+	struct device_node *np = pdev->dev.of_node;
+
+	pmc_regs = of_iomap(np, 0);
 	if (!pmc_regs)
 		return -ENOMEM;
 
-	pmc_dev = &ofdev->dev;
+	pmc_flag = PMC_SLEEP;
+	if (of_device_is_compatible(np, "fsl,mpc8536-pmc"))
+		pmc_flag |= PMC_DEEP_SLEEP;
+
+	if (of_device_is_compatible(np, "fsl,p1022-pmc"))
+		pmc_flag |= PMC_DEEP_SLEEP;
+
 	suspend_set_ops(&pmc_suspend_ops);
+
+	pr_info("Freescale PMC driver: sleep(standby)%s\n",
+		(pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
 	return 0;
 }
 
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index c6d0073..11d9f94 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -48,5 +48,10 @@ extern struct platform_diu_data_ops diu_ops;
 void fsl_hv_restart(char *cmd);
 void fsl_hv_halt(void);
 
+/*
+ * ccsrbar is u64 rather than phys_addr_t so that the assembly
+ * code can be compatible with both 32-bit & 36-bit.
+ */
+extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
 #endif
 #endif
-- 
1.6.4.1



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

* [PATCH v6 3/5] powerpc/85xx: add sleep and deep sleep support
@ 2012-06-26 10:25   ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel

From: Li Yang <leoli@freescale.com>

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

Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode
in addtion to the sleep PM mode.

While in deep sleep PM mode, additionally, the power supply is
removed from e500 core and most IP blocks. Only the blocks needed
to wake up the chip out of deep sleep are ON.

This patch supports 32-bit and 36-bit address space.

The sleep mode is equal to the Standby state in Linux. The deep sleep
mode is equal to the Suspend-to-RAM state of Linux Power Management.

Command to enter sleep mode.
  echo standby > /sys/power/state
Command to enter deep sleep mode.
  echo mem > /sys/power/state

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
Changes for v6:
 * changed the declaration of flush_dcache_L1()
 * some minor changes

 arch/powerpc/Kconfig                  |    2 +-
 arch/powerpc/include/asm/cacheflush.h |    2 +
 arch/powerpc/kernel/Makefile          |    3 +
 arch/powerpc/kernel/l2cache_85xx.S    |   53 +++
 arch/powerpc/platforms/85xx/Makefile  |    2 +-
 arch/powerpc/platforms/85xx/sleep.S   |  609 +++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_pmc.c         |   98 +++++-
 arch/powerpc/sysdev/fsl_soc.h         |    5 +
 8 files changed, 754 insertions(+), 20 deletions(-)
 create mode 100644 arch/powerpc/kernel/l2cache_85xx.S
 create mode 100644 arch/powerpc/platforms/85xx/sleep.S

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d6bacbe..6883769 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -673,7 +673,7 @@ config FSL_PCI
 config FSL_PMC
 	bool
 	default y
-	depends on SUSPEND && (PPC_85xx || PPC_86xx)
+	depends on SUSPEND && (PPC_85xx || PPC_86xx) && !PPC_E500MC
 	help
 	  Freescale MPC85xx/MPC86xx power management controller support
 	  (suspend/resume). For MPC83xx see platforms/83xx/suspend.c
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index b843e35..6c5f1c2 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -58,6 +58,8 @@ extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
 extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
 #endif
 
+extern void flush_dcache_L1(void);
+
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 	do { \
 		memcpy(dst, src, len); \
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index f5808a3..cb70dba 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP)		+= fadump.o
 ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)		+= idle_e500.o
 endif
+ifneq ($(CONFIG_PPC_E500MC),y)
+obj-$(CONFIG_PPC_85xx)		+= l2cache_85xx.o
+endif
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o
diff --git a/arch/powerpc/kernel/l2cache_85xx.S b/arch/powerpc/kernel/l2cache_85xx.S
new file mode 100644
index 0000000..b0b7d1c
--- /dev/null
+++ b/arch/powerpc/kernel/l2cache_85xx.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *	Scott Wood <scottwood@freescale.com>
+ *	Dave Liu <daveliu@freescale.com>
+ * implement the L2 cache operations of e500 based L2 controller
+ *
+ * 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/reg.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+	.section .text
+
+	/* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(flush_disable_L2)
+	/* It's a write-through cache, so only invalidation is needed. */
+	mbar
+	isync
+	lwz	r4, 0(r3)
+	li	r5, 1
+	rlwimi	r4, r5, 30, 0xc0000000
+	stw	r4, 0(r3)
+
+	/* Wait for the invalidate to finish */
+1:	lwz	r4, 0(r3)
+	andis.	r4, r4, 0x4000
+	bne	1b
+	mbar
+
+	blr
+
+	/* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(invalidate_enable_L2)
+	mbar
+	isync
+	lwz	r4, 0(r3)
+	li	r5, 3
+	rlwimi	r4, r5, 30, 0xc0000000
+	stw	r4, 0(r3)
+
+	/* Wait for the invalidate to finish */
+1:	lwz	r4, 0(r3)
+	andis.	r4, r4, 0x4000
+	bne	1b
+	mbar
+
+	blr
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 2125d4c..d154e39 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_SMP) += smp.o
 
-obj-y += common.o
+obj-y += common.o sleep.o
 
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..b272f0c
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,609 @@
+/*
+ * Enter and leave deep sleep/sleep state on MPC85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (C) 2006-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+
+#define SS_TB		0x00
+#define SS_HID		0x08 /* 2 HIDs */
+#define SS_IAC		0x10 /* 2 IACs */
+#define SS_DAC		0x18 /* 2 DACs */
+#define SS_DBCR		0x20 /* 3 DBCRs */
+#define SS_PID		0x2c /* 3 PIDs */
+#define SS_SPRG		0x38 /* 8 SPRGs */
+#define SS_IVOR		0x58 /* 20 interrupt vectors */
+#define SS_TCR		0xa8
+#define SS_BUCSR	0xac
+#define SS_L1CSR	0xb0 /* 2 L1CSRs */
+#define SS_MSR		0xb8
+#define SS_USPRG	0xbc
+#define SS_GPREG	0xc0 /* r12-r31 */
+#define SS_LR		0x110
+#define SS_CR		0x114
+#define SS_SP		0x118
+#define SS_CURRENT	0x11c
+#define SS_IVPR		0x120
+#define SS_BPTR		0x124
+
+
+#define STATE_SAVE_SIZE 0x128
+
+	.section .data
+	.align	5
+mpc85xx_sleep_save_area:
+	.space	STATE_SAVE_SIZE
+ccsrbase_low:
+	.long	0
+ccsrbase_high:
+	.long	0
+powmgtreq:
+	.long	0
+
+	.section .text
+	.align	12
+
+	/*
+	 * r3 = high word of physical address of CCSR
+	 * r4 = low word of physical address of CCSR
+	 * r5 = JOG or deep sleep request
+	 *      JOG-0x00200000, deep sleep-0x00100000
+	 */
+_GLOBAL(mpc85xx_enter_deep_sleep)
+	lis	r6, ccsrbase_low@ha
+	stw	r4, ccsrbase_low@l(r6)
+	lis	r6, ccsrbase_high@ha
+	stw	r3, ccsrbase_high@l(r6)
+
+	lis	r6, powmgtreq@ha
+	stw	r5, powmgtreq@l(r6)
+
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	mfspr	r5, SPRN_HID0
+	mfspr	r6, SPRN_HID1
+
+	stw	r5, SS_HID+0(r10)
+	stw	r6, SS_HID+4(r10)
+
+	mfspr	r4, SPRN_IAC1
+	mfspr	r5, SPRN_IAC2
+	mfspr	r6, SPRN_DAC1
+	mfspr	r7, SPRN_DAC2
+
+	stw	r4, SS_IAC+0(r10)
+	stw	r5, SS_IAC+4(r10)
+	stw	r6, SS_DAC+0(r10)
+	stw	r7, SS_DAC+4(r10)
+
+	mfspr	r4, SPRN_DBCR0
+	mfspr	r5, SPRN_DBCR1
+	mfspr	r6, SPRN_DBCR2
+
+	stw	r4, SS_DBCR+0(r10)
+	stw	r5, SS_DBCR+4(r10)
+	stw	r6, SS_DBCR+8(r10)
+
+	mfspr	r4, SPRN_PID0
+	mfspr	r5, SPRN_PID1
+	mfspr	r6, SPRN_PID2
+
+	stw	r4, SS_PID+0(r10)
+	stw	r5, SS_PID+4(r10)
+	stw	r6, SS_PID+8(r10)
+
+	mfspr	r4, SPRN_SPRG0
+	mfspr	r5, SPRN_SPRG1
+	mfspr	r6, SPRN_SPRG2
+	mfspr	r7, SPRN_SPRG3
+
+	stw	r4, SS_SPRG+0x00(r10)
+	stw	r5, SS_SPRG+0x04(r10)
+	stw	r6, SS_SPRG+0x08(r10)
+	stw	r7, SS_SPRG+0x0c(r10)
+
+	mfspr	r4, SPRN_SPRG4
+	mfspr	r5, SPRN_SPRG5
+	mfspr	r6, SPRN_SPRG6
+	mfspr	r7, SPRN_SPRG7
+
+	stw	r4, SS_SPRG+0x10(r10)
+	stw	r5, SS_SPRG+0x14(r10)
+	stw	r6, SS_SPRG+0x18(r10)
+	stw	r7, SS_SPRG+0x1c(r10)
+
+	mfspr	r4, SPRN_IVPR
+	stw	r4, SS_IVPR(r10)
+
+	mfspr	r4, SPRN_IVOR0
+	mfspr	r5, SPRN_IVOR1
+	mfspr	r6, SPRN_IVOR2
+	mfspr	r7, SPRN_IVOR3
+
+	stw	r4, SS_IVOR+0x00(r10)
+	stw	r5, SS_IVOR+0x04(r10)
+	stw	r6, SS_IVOR+0x08(r10)
+	stw	r7, SS_IVOR+0x0c(r10)
+
+	mfspr	r4, SPRN_IVOR4
+	mfspr	r5, SPRN_IVOR5
+	mfspr	r6, SPRN_IVOR6
+	mfspr	r7, SPRN_IVOR7
+
+	stw	r4, SS_IVOR+0x10(r10)
+	stw	r5, SS_IVOR+0x14(r10)
+	stw	r6, SS_IVOR+0x18(r10)
+	stw	r7, SS_IVOR+0x1c(r10)
+
+	mfspr	r4, SPRN_IVOR8
+	mfspr	r5, SPRN_IVOR9
+	mfspr	r6, SPRN_IVOR10
+	mfspr	r7, SPRN_IVOR11
+
+	stw	r4, SS_IVOR+0x20(r10)
+	stw	r5, SS_IVOR+0x24(r10)
+	stw	r6, SS_IVOR+0x28(r10)
+	stw	r7, SS_IVOR+0x2c(r10)
+
+	mfspr	r4, SPRN_IVOR12
+	mfspr	r5, SPRN_IVOR13
+	mfspr	r6, SPRN_IVOR14
+	mfspr	r7, SPRN_IVOR15
+
+	stw	r4, SS_IVOR+0x30(r10)
+	stw	r5, SS_IVOR+0x34(r10)
+	stw	r6, SS_IVOR+0x38(r10)
+	stw	r7, SS_IVOR+0x3c(r10)
+
+	mfspr	r4, SPRN_IVOR32
+	mfspr	r5, SPRN_IVOR33
+	mfspr	r6, SPRN_IVOR34
+	mfspr	r7, SPRN_IVOR35
+
+	stw	r4, SS_IVOR+0x40(r10)
+	stw	r5, SS_IVOR+0x44(r10)
+	stw	r6, SS_IVOR+0x48(r10)
+	stw	r7, SS_IVOR+0x4c(r10)
+
+	mfspr	r4, SPRN_TCR
+	mfspr	r5, SPRN_BUCSR
+	mfspr	r6, SPRN_L1CSR0
+	mfspr	r7, SPRN_L1CSR1
+	mfspr	r8, SPRN_USPRG0
+
+	stw	r4, SS_TCR(r10)
+	stw	r5, SS_BUCSR(r10)
+	stw	r6, SS_L1CSR+0(r10)
+	stw	r7, SS_L1CSR+4(r10)
+	stw	r8, SS_USPRG+0(r10)
+
+	stmw	r12, SS_GPREG(r10)
+
+	mfmsr	r4
+	mflr	r5
+	mfcr	r6
+
+	stw	r4, SS_MSR(r10)
+	stw	r5, SS_LR(r10)
+	stw	r6, SS_CR(r10)
+	stw	r1, SS_SP(r10)
+	stw	r2, SS_CURRENT(r10)
+
+1:	mftbu	r4
+	mftb	r5
+	mftbu	r6
+	cmpw	r4, r6
+	bne	1b
+
+	stw	r4, SS_TB+0(r10)
+	stw	r5, SS_TB+4(r10)
+
+	lis	r5, ccsrbase_low@ha
+	lwz	r4, ccsrbase_low@l(r5)
+	lis	r5, ccsrbase_high@ha
+	lwz	r3, ccsrbase_high@l(r5)
+
+	/* Disable machine checks and critical exceptions */
+	mfmsr	r5
+	rlwinm	r5, r5, 0, ~MSR_CE
+	rlwinm	r5, r5, 0, ~MSR_ME
+	mtmsr	r5
+	isync
+
+	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
+	lis	r5, 0x100f
+	mtspr	SPRN_MAS0, r5
+	lis	r5, 0xc000
+	ori	r5, r5, 0x0500
+	mtspr	SPRN_MAS1, r5
+	lis	r5, 0xf000
+	ori	r5, r5, 0x000a
+	mtspr	SPRN_MAS2, r5
+	rlwinm	r5, r4, 0, 0xfffff000
+	ori	r5, r5, 0x0005
+	mtspr	SPRN_MAS3, r5
+	mtspr	SPRN_MAS7, r3
+	isync
+	tlbwe
+	isync
+
+	lis	r3, 0xf000
+	lwz	r4, 0x20(r3)
+	stw	r4, SS_BPTR(r10)
+
+	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 */
+	bl	flush_disable_L2
+	bl	__flush_disable_L1
+
+	/* Enable I-cache, so as not to upset the bus
+	 * with our loop.
+	 */
+
+	mfspr	r4, SPRN_L1CSR1
+	ori	r4, r4, 1
+	mtspr	SPRN_L1CSR1, r4
+	isync
+
+	/* Set boot page translation */
+	lis	r3, 0xf000
+	lis	r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
+	ori	r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
+	rlwinm	r4, r4, 20, 0x000fffff
+	oris	r4, r4, 0x8000
+	stw	r4, 0x20(r3)
+	lwz	r4, 0x20(r3)		/* read-back to flush write */
+	twi	0, r4, 0
+	isync
+
+	/* Disable the decrementer */
+	mfspr	r4, SPRN_TCR
+	rlwinm	r4, r4, 0, ~TCR_DIE
+	mtspr	SPRN_TCR, r4
+
+	mfspr	r4, SPRN_TSR
+	oris	r4, r4, TSR_DIS@h
+	mtspr	SPRN_TSR, r4
+
+	/* set PMRCCR[VRCNT] to wait power stable for 40ms */
+	lis	r3, 0xf00e
+	lwz	r4, 0x84(r3)
+	clrlwi	r4, r4, 16
+	oris	r4, r4, 0x12a3
+	stw	r4, 0x84(r3)
+	lwz	r4, 0x84(r3)
+
+	/* set deep sleep bit in POWMGTSCR */
+	lis	r3, powmgtreq@ha
+	lwz	r8, powmgtreq@l(r3)
+
+	lis	r3, 0xf00e
+	lwz	r4, 0x80(r3)
+	or	r4, r4, r8
+	stw	r4, 0x80(r3)
+	lwz	r4, 0x80(r3)		/* read-back to flush write */
+	twi	0, r4, 0
+	isync
+
+	mftb	r5
+1:	/* spin until either we enter deep sleep, or the sleep process is
+	 * aborted due to a pending wakeup event.  Wait some time between
+	 * accesses, so we don't flood the bus and prevent the pmc from
+	 * detecting an idle system.
+	 */
+
+	mftb	r4
+	subf	r7, r5, r4
+	cmpwi	r7, 1000
+	blt	1b
+	mr	r5, r4
+
+	lwz	r6, 0x80(r3)
+	andis.	r6, r6, 0x0010
+	bne	1b
+	b	2f
+
+2:	mfspr	r4, SPRN_PIR
+	andi.	r4, r4, 1
+99:	bne	99b
+
+	/* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
+	lis	r4, 0x1001
+	mtspr	SPRN_MAS0, r4
+	lis	r4, 0xc000
+	ori	r4, r4, 0x0800
+	mtspr	SPRN_MAS1, r4
+	li	r4, 0
+	mtspr	SPRN_MAS2, r4
+	li	r4, 0x0015
+	mtspr	SPRN_MAS3, r4
+	li	r4, 0
+	mtspr	SPRN_MAS7, r4
+	isync
+	tlbwe
+	isync
+
+	lis	r3, (3f - PAGE_OFFSET)@h
+	ori	r3, r3, (3f - PAGE_OFFSET)@l
+	mtctr	r3
+	bctr
+
+	/* Locate the resume vector in the last word of the current page. */
+	. = mpc85xx_enter_deep_sleep + 0xffc
+mpc85xx_deep_resume:
+	b	2b
+
+3:
+	/* Restore the contents of TLB1[0].  It is assumed that it covers
+	 * the currently executing code and the sleep save area, and that
+	 * it does not alias our temporary mapping (which is at virtual zero).
+	 */
+	lis	r3, (TLBCAM - PAGE_OFFSET)@h
+	ori	r3, r3, (TLBCAM - PAGE_OFFSET)@l
+
+	lwz	r4, 0(r3)
+	lwz	r5, 4(r3)
+	lwz	r6, 8(r3)
+	lwz	r7, 12(r3)
+	lwz	r8, 16(r3)
+
+	mtspr	SPRN_MAS0, r4
+	mtspr	SPRN_MAS1, r5
+	mtspr	SPRN_MAS2, r6
+	mtspr	SPRN_MAS3, r7
+	mtspr	SPRN_MAS7, r8
+
+	isync
+	tlbwe
+	isync
+
+	/* Access the ccsrbase address with TLB1[0] */
+	lis	r5, ccsrbase_low@ha
+	lwz	r4, ccsrbase_low@l(r5)
+	lis	r5, ccsrbase_high@ha
+	lwz	r3, ccsrbase_high@l(r5)
+
+	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
+	lis	r5, 0x100f
+	mtspr	SPRN_MAS0, r5
+	lis	r5, 0xc000
+	ori	r5, r5, 0x0500
+	mtspr	SPRN_MAS1, r5
+	lis	r5, 0xf000
+	ori	r5, r5, 0x000a
+	mtspr	SPRN_MAS2, r5
+	rlwinm	r5, r4, 0, 0xfffff000
+	ori	r5, r5, 0x0005
+	mtspr	SPRN_MAS3, r5
+	mtspr	SPRN_MAS7, r3
+	isync
+	tlbwe
+	isync
+
+	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 */
+	bl	invalidate_enable_L2
+
+	/* Access the MEM(r10) with TLB1[0] */
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	lis	r3, 0xf000
+	lwz	r4, SS_BPTR(r10)
+	stw	r4, 0x20(r3)		/* restore BPTR */
+
+	/* Program shift running space to PAGE_OFFSET */
+	mfmsr	r3
+	lis	r4, 1f@h
+	ori	r4, r4, 1f@l
+
+	mtsrr1	r3
+	mtsrr0	r4
+	rfi
+
+1:	/* Restore the rest of TLB1, in ascending order so that
+	 * the TLB1[1] gets invalidated first.
+	 *
+	 * XXX: It's better to invalidate the temporary mapping
+	 * TLB1[15] for CCSR before restore any TLB1 entry include 0.
+	 */
+	lis	r4, 0x100f
+	mtspr	SPRN_MAS0, r4
+	lis	r4, 0
+	mtspr	SPRN_MAS1, r4
+	isync
+	tlbwe
+	isync
+
+	lis	r3, (TLBCAM + 5*4 - 4)@h
+	ori	r3, r3, (TLBCAM + 5*4 - 4)@l
+	li	r4, 15
+	mtctr	r4
+
+2:
+	lwz	r5, 4(r3)
+	lwz	r6, 8(r3)
+	lwz	r7, 12(r3)
+	lwz	r8, 16(r3)
+	lwzu	r9, 20(r3)
+
+	mtspr	SPRN_MAS0, r5
+	mtspr	SPRN_MAS1, r6
+	mtspr	SPRN_MAS2, r7
+	mtspr	SPRN_MAS3, r8
+	mtspr	SPRN_MAS7, r9
+
+	isync
+	tlbwe
+	isync
+	bdnz	2b
+
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	lwz	r5, SS_HID+0(r10)
+	lwz	r6, SS_HID+4(r10)
+
+	isync
+	mtspr	SPRN_HID0, r5
+	isync
+
+	msync
+	mtspr	SPRN_HID1, r6
+	isync
+
+	lwz	r4, SS_IAC+0(r10)
+	lwz	r5, SS_IAC+4(r10)
+	lwz	r6, SS_DAC+0(r10)
+	lwz	r7, SS_DAC+4(r10)
+
+	mtspr	SPRN_IAC1, r4
+	mtspr	SPRN_IAC2, r5
+	mtspr	SPRN_DAC1, r6
+	mtspr	SPRN_DAC2, r7
+
+	lwz	r4, SS_DBCR+0(r10)
+	lwz	r5, SS_DBCR+4(r10)
+	lwz	r6, SS_DBCR+8(r10)
+
+	mtspr	SPRN_DBCR0, r4
+	mtspr	SPRN_DBCR1, r5
+	mtspr	SPRN_DBCR2, r6
+
+	lwz	r4, SS_PID+0(r10)
+	lwz	r5, SS_PID+4(r10)
+	lwz	r6, SS_PID+8(r10)
+
+	mtspr	SPRN_PID0, r4
+	mtspr	SPRN_PID1, r5
+	mtspr	SPRN_PID2, r6
+
+	lwz	r4, SS_SPRG+0x00(r10)
+	lwz	r5, SS_SPRG+0x04(r10)
+	lwz	r6, SS_SPRG+0x08(r10)
+	lwz	r7, SS_SPRG+0x0c(r10)
+
+	mtspr	SPRN_SPRG0, r4
+	mtspr	SPRN_SPRG1, r5
+	mtspr	SPRN_SPRG2, r6
+	mtspr	SPRN_SPRG3, r7
+
+	lwz	r4, SS_SPRG+0x10(r10)
+	lwz	r5, SS_SPRG+0x14(r10)
+	lwz	r6, SS_SPRG+0x18(r10)
+	lwz	r7, SS_SPRG+0x1c(r10)
+
+	mtspr	SPRN_SPRG4, r4
+	mtspr	SPRN_SPRG5, r5
+	mtspr	SPRN_SPRG6, r6
+	mtspr	SPRN_SPRG7, r7
+
+	lwz	r4, SS_IVPR(r10)
+	mtspr	SPRN_IVPR, r4
+
+	lwz	r4, SS_IVOR+0x00(r10)
+	lwz	r5, SS_IVOR+0x04(r10)
+	lwz	r6, SS_IVOR+0x08(r10)
+	lwz	r7, SS_IVOR+0x0c(r10)
+
+	mtspr	SPRN_IVOR0, r4
+	mtspr	SPRN_IVOR1, r5
+	mtspr	SPRN_IVOR2, r6
+	mtspr	SPRN_IVOR3, r7
+
+	lwz	r4, SS_IVOR+0x10(r10)
+	lwz	r5, SS_IVOR+0x14(r10)
+	lwz	r6, SS_IVOR+0x18(r10)
+	lwz	r7, SS_IVOR+0x1c(r10)
+
+	mtspr	SPRN_IVOR4, r4
+	mtspr	SPRN_IVOR5, r5
+	mtspr	SPRN_IVOR6, r6
+	mtspr	SPRN_IVOR7, r7
+
+	lwz	r4, SS_IVOR+0x20(r10)
+	lwz	r5, SS_IVOR+0x24(r10)
+	lwz	r6, SS_IVOR+0x28(r10)
+	lwz	r7, SS_IVOR+0x2c(r10)
+
+	mtspr	SPRN_IVOR8, r4
+	mtspr	SPRN_IVOR9, r5
+	mtspr	SPRN_IVOR10, r6
+	mtspr	SPRN_IVOR11, r7
+
+	lwz	r4, SS_IVOR+0x30(r10)
+	lwz	r5, SS_IVOR+0x34(r10)
+	lwz	r6, SS_IVOR+0x38(r10)
+	lwz	r7, SS_IVOR+0x3c(r10)
+
+	mtspr	SPRN_IVOR12, r4
+	mtspr	SPRN_IVOR13, r5
+	mtspr	SPRN_IVOR14, r6
+	mtspr	SPRN_IVOR15, r7
+
+	lwz	r4, SS_IVOR+0x40(r10)
+	lwz	r5, SS_IVOR+0x44(r10)
+	lwz	r6, SS_IVOR+0x48(r10)
+	lwz	r7, SS_IVOR+0x4c(r10)
+
+	mtspr	SPRN_IVOR32, r4
+	mtspr	SPRN_IVOR33, r5
+	mtspr	SPRN_IVOR34, r6
+	mtspr	SPRN_IVOR35, r7
+
+	lwz	r4, SS_TCR(r10)
+	lwz	r5, SS_BUCSR(r10)
+	lwz	r6, SS_L1CSR+0(r10)
+	lwz	r7, SS_L1CSR+4(r10)
+	lwz	r8, SS_USPRG+0(r10)
+
+	mtspr	SPRN_TCR, r4
+	mtspr	SPRN_BUCSR, r5
+
+	msync
+	isync
+	mtspr	SPRN_L1CSR0, r6
+	isync
+
+	mtspr	SPRN_L1CSR1, r7
+	isync
+
+	mtspr	SPRN_USPRG0, r8
+
+	lmw	r12, SS_GPREG(r10)
+
+	lwz	r1, SS_SP(r10)
+	lwz	r2, SS_CURRENT(r10)
+	lwz	r4, SS_MSR(r10)
+	lwz	r5, SS_LR(r10)
+	lwz	r6, SS_CR(r10)
+
+	msync
+	mtmsr	r4
+	isync
+
+	mtlr	r5
+	mtcr	r6
+
+	li	r4, 0
+	mtspr	SPRN_TBWL, r4
+
+	lwz	r4, SS_TB+0(r10)
+	lwz	r5, SS_TB+4(r10)
+
+	mtspr	SPRN_TBWU, r4
+	mtspr	SPRN_TBWL, r5
+
+	lis	r3, 1
+	mtdec	r3
+
+	blr
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 592a0f8..45718c5 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -2,6 +2,7 @@
  * Suspend/resume support
  *
  * Copyright 2009  MontaVista Software, Inc.
+ * Copyright 2010-2012 Freescale Semiconductor Inc.
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
  *
@@ -19,39 +20,89 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/of_platform.h>
+#include <linux/pm.h>
+#include <asm/cacheflush.h>
+#include <asm/switch_to.h>
+
+#include <sysdev/fsl_soc.h>
 
 struct pmc_regs {
+	/* 0xe0070: Device disable control register */
 	__be32 devdisr;
+	/* 0xe0074: 2nd Device disable control register */
 	__be32 devdisr2;
-	__be32 :32;
-	__be32 :32;
-	__be32 pmcsr;
-#define PMCSR_SLP	(1 << 17)
+	__be32 res1;
+	/* 0xe007c: Power Management Jog Control Register */
+	__be32 pmjcr;
+	/* 0xe0080: Power management control and status register */
+	__be32 powmgtcsr;
+#define POWMGTCSR_SLP		0x00020000
+#define POWMGTCSR_DPSLP		0x00100000
+	__be32 res3[2];
+	/* 0xe008c: Power management clock disable register */
+	__be32 pmcdr;
 };
 
-static struct device *pmc_dev;
 static struct pmc_regs __iomem *pmc_regs;
+static unsigned int pmc_flag;
+
+#define PMC_SLEEP	0x1
+#define PMC_DEEP_SLEEP	0x2
 
 static int pmc_suspend_enter(suspend_state_t state)
 {
-	int ret;
+	int ret = 0;
+
+	switch (state) {
+#ifdef CONFIG_PPC_85xx
+	case PM_SUSPEND_MEM:
+#ifdef CONFIG_SPE
+		enable_kernel_spe();
+#endif
+		enable_kernel_fp();
+
+		pr_debug("%s: Entering deep sleep\n", __func__);
+
+		local_irq_disable();
+		mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_DPSLP);
+
+		pr_debug("%s: Resumed from deep sleep\n", __func__);
+		break;
+#endif
 
-	setbits32(&pmc_regs->pmcsr, PMCSR_SLP);
-	/* At this point, the CPU is asleep. */
+	case PM_SUSPEND_STANDBY:
+		local_irq_disable();
+#ifdef CONFIG_PPC_85xx
+		flush_dcache_L1();
+#endif
+		setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);
+		/* At this point, the CPU is asleep. */
 
-	/* Upon resume, wait for SLP bit to be clear. */
-	ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0,
-				 10000, 10) ? 0 : -ETIMEDOUT;
-	if (ret)
-		dev_err(pmc_dev, "tired waiting for SLP bit to clear\n");
+		/* Upon resume, wait for SLP bit to be clear. */
+		ret = spin_event_timeout(
+			(in_be32(&pmc_regs->powmgtcsr) & POWMGTCSR_SLP) == 0,
+			10000, 10);
+		if (!ret) {
+			pr_err("%s: timeout waiting for SLP bit "
+				"to be cleared\n", __func__);
+			ret = -EINVAL;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+
+	}
 	return ret;
 }
 
 static int pmc_suspend_valid(suspend_state_t state)
 {
-	if (state != PM_SUSPEND_STANDBY)
+	if (((pmc_flag & PMC_SLEEP) && (state == PM_SUSPEND_STANDBY)) ||
+	    ((pmc_flag & PMC_DEEP_SLEEP) && (state == PM_SUSPEND_MEM)))
+		return 1;
+	else
 		return 0;
-	return 1;
 }
 
 static const struct platform_suspend_ops pmc_suspend_ops = {
@@ -59,14 +110,25 @@ static const struct platform_suspend_ops pmc_suspend_ops = {
 	.enter = pmc_suspend_enter,
 };
 
-static int pmc_probe(struct platform_device *ofdev)
+static int pmc_probe(struct platform_device *pdev)
 {
-	pmc_regs = of_iomap(ofdev->dev.of_node, 0);
+	struct device_node *np = pdev->dev.of_node;
+
+	pmc_regs = of_iomap(np, 0);
 	if (!pmc_regs)
 		return -ENOMEM;
 
-	pmc_dev = &ofdev->dev;
+	pmc_flag = PMC_SLEEP;
+	if (of_device_is_compatible(np, "fsl,mpc8536-pmc"))
+		pmc_flag |= PMC_DEEP_SLEEP;
+
+	if (of_device_is_compatible(np, "fsl,p1022-pmc"))
+		pmc_flag |= PMC_DEEP_SLEEP;
+
 	suspend_set_ops(&pmc_suspend_ops);
+
+	pr_info("Freescale PMC driver: sleep(standby)%s\n",
+		(pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
 	return 0;
 }
 
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index c6d0073..11d9f94 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -48,5 +48,10 @@ extern struct platform_diu_data_ops diu_ops;
 void fsl_hv_restart(char *cmd);
 void fsl_hv_halt(void);
 
+/*
+ * ccsrbar is u64 rather than phys_addr_t so that the assembly
+ * code can be compatible with both 32-bit & 36-bit.
+ */
+extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
 #endif
 #endif
-- 
1.6.4.1

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

* [PATCH v6 4/5] fsl_pmc: Add API to enable device as wakeup event source
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-26 10:25   ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel, galak, leoli

Add APIs for setting wakeup source and lossless Ethernet in low power modes.
These APIs can be used by wake-on-packet feature.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
Changes for v6:
 * changed the parameter of mpc85xx_pmc_set_wake()
 * set an initial value to PMCDR register

 arch/powerpc/sysdev/fsl_pmc.c |   77 ++++++++++++++++++++++++++++++++++++++++-
 arch/powerpc/sysdev/fsl_soc.h |   12 ++++++
 2 files changed, 88 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 45718c5..b6c8c8f 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -38,6 +38,7 @@ struct pmc_regs {
 	__be32 powmgtcsr;
 #define POWMGTCSR_SLP		0x00020000
 #define POWMGTCSR_DPSLP		0x00100000
+#define POWMGTCSR_LOSSLESS	0x00400000
 	__be32 res3[2];
 	/* 0xe008c: Power management clock disable register */
 	__be32 pmcdr;
@@ -48,6 +49,77 @@ static unsigned int pmc_flag;
 
 #define PMC_SLEEP	0x1
 #define PMC_DEEP_SLEEP	0x2
+#define PMC_LOSSLESS	0x4
+
+#define PMCDR_MASK_INIT		0x00e008e0
+
+/**
+ * mpc85xx_pmc_set_wake - enable devices as wakeup event source
+ * @dev: a device affected
+ * @enable: True to enable event generation; false to disable
+ *
+ * This enables the device as a wakeup event source, or disables it.
+ *
+ * RETURN VALUE:
+ * 0 is returned on success.
+ * -EINVAL is returned if device is not supposed to wake up the system.
+ * -ENODEV is returned if PMC is unavailable.
+ * Error code depending on the platform is returned if both the platform and
+ * the native mechanism fail to enable the generation of wake-up events
+ */
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+	int ret = 0;
+	struct device_node *clk_np;
+	const u32 *prop;
+	u32 pmcdr_mask;
+
+	if (!pmc_regs) {
+		pr_err("%s: PMC is unavailable\n", __func__);
+		return -ENODEV;
+	}
+
+	if (enable && !device_may_wakeup(dev))
+		return -EINVAL;
+
+	clk_np = of_parse_phandle(dev->of_node, "fsl,pmc-handle", 0);
+	if (!clk_np)
+		return -EINVAL;
+
+	prop = of_get_property(clk_np, "fsl,pmcdr-mask", NULL);
+	if (!prop) {
+		ret = -EINVAL;
+		goto out;
+	}
+	pmcdr_mask = be32_to_cpup(prop);
+
+	if (enable)
+		/* clear to enable clock in low power mode */
+		clrbits32(&pmc_regs->pmcdr, pmcdr_mask);
+	else
+		setbits32(&pmc_regs->pmcdr, pmcdr_mask);
+
+out:
+	of_node_put(clk_np);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_wake);
+
+/**
+ * mpc85xx_pmc_set_lossless_ethernet - enable lossless ethernet
+ * in (deep) sleep mode
+ * @enable: True to enable event generation; false to disable
+ */
+void mpc85xx_pmc_set_lossless_ethernet(int enable)
+{
+	if (pmc_flag & PMC_LOSSLESS) {
+		if (enable)
+			setbits32(&pmc_regs->powmgtcsr,	POWMGTCSR_LOSSLESS);
+		else
+			clrbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+	}
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_lossless_ethernet);
 
 static int pmc_suspend_enter(suspend_state_t state)
 {
@@ -123,7 +195,10 @@ static int pmc_probe(struct platform_device *pdev)
 		pmc_flag |= PMC_DEEP_SLEEP;
 
 	if (of_device_is_compatible(np, "fsl,p1022-pmc"))
-		pmc_flag |= PMC_DEEP_SLEEP;
+		pmc_flag |= PMC_DEEP_SLEEP | PMC_LOSSLESS;
+
+	/* Init the Power Management Clock Disable Register. */
+	setbits32(&pmc_regs->pmcdr, PMCDR_MASK_INIT);
 
 	suspend_set_ops(&pmc_suspend_ops);
 
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 11d9f94..b1510ef 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -3,6 +3,7 @@
 #ifdef __KERNEL__
 
 #include <asm/mmu.h>
+#include <linux/platform_device.h>
 
 struct spi_device;
 
@@ -21,6 +22,17 @@ struct device_node;
 
 extern void fsl_rstcr_restart(char *cmd);
 
+#ifdef CONFIG_FSL_PMC
+extern int mpc85xx_pmc_set_wake(struct device *dev, bool enable);
+extern void mpc85xx_pmc_set_lossless_ethernet(int enable);
+#else
+static inline int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+	return -ENODEV;
+}
+#define mpc85xx_pmc_set_lossless_ethernet(enable)	do { } while (0)
+#endif
+
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
 /* The different ports that the DIU can be connected to */
-- 
1.6.4.1



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

* [PATCH v6 4/5] fsl_pmc: Add API to enable device as wakeup event source
@ 2012-06-26 10:25   ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel

Add APIs for setting wakeup source and lossless Ethernet in low power modes.
These APIs can be used by wake-on-packet feature.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
Changes for v6:
 * changed the parameter of mpc85xx_pmc_set_wake()
 * set an initial value to PMCDR register

 arch/powerpc/sysdev/fsl_pmc.c |   77 ++++++++++++++++++++++++++++++++++++++++-
 arch/powerpc/sysdev/fsl_soc.h |   12 ++++++
 2 files changed, 88 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 45718c5..b6c8c8f 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -38,6 +38,7 @@ struct pmc_regs {
 	__be32 powmgtcsr;
 #define POWMGTCSR_SLP		0x00020000
 #define POWMGTCSR_DPSLP		0x00100000
+#define POWMGTCSR_LOSSLESS	0x00400000
 	__be32 res3[2];
 	/* 0xe008c: Power management clock disable register */
 	__be32 pmcdr;
@@ -48,6 +49,77 @@ static unsigned int pmc_flag;
 
 #define PMC_SLEEP	0x1
 #define PMC_DEEP_SLEEP	0x2
+#define PMC_LOSSLESS	0x4
+
+#define PMCDR_MASK_INIT		0x00e008e0
+
+/**
+ * mpc85xx_pmc_set_wake - enable devices as wakeup event source
+ * @dev: a device affected
+ * @enable: True to enable event generation; false to disable
+ *
+ * This enables the device as a wakeup event source, or disables it.
+ *
+ * RETURN VALUE:
+ * 0 is returned on success.
+ * -EINVAL is returned if device is not supposed to wake up the system.
+ * -ENODEV is returned if PMC is unavailable.
+ * Error code depending on the platform is returned if both the platform and
+ * the native mechanism fail to enable the generation of wake-up events
+ */
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+	int ret = 0;
+	struct device_node *clk_np;
+	const u32 *prop;
+	u32 pmcdr_mask;
+
+	if (!pmc_regs) {
+		pr_err("%s: PMC is unavailable\n", __func__);
+		return -ENODEV;
+	}
+
+	if (enable && !device_may_wakeup(dev))
+		return -EINVAL;
+
+	clk_np = of_parse_phandle(dev->of_node, "fsl,pmc-handle", 0);
+	if (!clk_np)
+		return -EINVAL;
+
+	prop = of_get_property(clk_np, "fsl,pmcdr-mask", NULL);
+	if (!prop) {
+		ret = -EINVAL;
+		goto out;
+	}
+	pmcdr_mask = be32_to_cpup(prop);
+
+	if (enable)
+		/* clear to enable clock in low power mode */
+		clrbits32(&pmc_regs->pmcdr, pmcdr_mask);
+	else
+		setbits32(&pmc_regs->pmcdr, pmcdr_mask);
+
+out:
+	of_node_put(clk_np);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_wake);
+
+/**
+ * mpc85xx_pmc_set_lossless_ethernet - enable lossless ethernet
+ * in (deep) sleep mode
+ * @enable: True to enable event generation; false to disable
+ */
+void mpc85xx_pmc_set_lossless_ethernet(int enable)
+{
+	if (pmc_flag & PMC_LOSSLESS) {
+		if (enable)
+			setbits32(&pmc_regs->powmgtcsr,	POWMGTCSR_LOSSLESS);
+		else
+			clrbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+	}
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_lossless_ethernet);
 
 static int pmc_suspend_enter(suspend_state_t state)
 {
@@ -123,7 +195,10 @@ static int pmc_probe(struct platform_device *pdev)
 		pmc_flag |= PMC_DEEP_SLEEP;
 
 	if (of_device_is_compatible(np, "fsl,p1022-pmc"))
-		pmc_flag |= PMC_DEEP_SLEEP;
+		pmc_flag |= PMC_DEEP_SLEEP | PMC_LOSSLESS;
+
+	/* Init the Power Management Clock Disable Register. */
+	setbits32(&pmc_regs->pmcdr, PMCDR_MASK_INIT);
 
 	suspend_set_ops(&pmc_suspend_ops);
 
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 11d9f94..b1510ef 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -3,6 +3,7 @@
 #ifdef __KERNEL__
 
 #include <asm/mmu.h>
+#include <linux/platform_device.h>
 
 struct spi_device;
 
@@ -21,6 +22,17 @@ struct device_node;
 
 extern void fsl_rstcr_restart(char *cmd);
 
+#ifdef CONFIG_FSL_PMC
+extern int mpc85xx_pmc_set_wake(struct device *dev, bool enable);
+extern void mpc85xx_pmc_set_lossless_ethernet(int enable);
+#else
+static inline int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+	return -ENODEV;
+}
+#define mpc85xx_pmc_set_lossless_ethernet(enable)	do { } while (0)
+#endif
+
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
 /* The different ports that the DIU can be connected to */
-- 
1.6.4.1

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

* [PATCH v6 5/5] powerpc/85xx: add support to JOG feature using cpufreq interface
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-26 10:25   ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel, galak, leoli

Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
a dynamic mechanism to lower or raise the CPU core clock at runtime.

This patch adds the support to change CPU frequency using the standard
cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
2:1, 5:2, 3:1, 7:2 and 4:1.

Two CPU cores on P1022 must not in the low power state during the frequency
transition. The driver uses a atomic counter to meet the requirement.

The jog mode frequency transition process on the MPC8536 is similar to
the deep sleep process. The driver need save the CPU state and restore
it after CPU warm reset.

Note:
 * The I/O peripherals such as PCIe and eTSEC may lose packets during
   the jog mode frequency transition.
 * The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
   Subsequent revisions of MPC8536 have corrected the erratum.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v6:
 * changed mpc85xx_jog_probe()
 * call mpc85xx_jog_probe() in arch/powerpc/sysdev/fsl_pmc.c
 * removed changes of kernel/cpu.c

 arch/powerpc/platforms/85xx/Makefile      |    1 +
 arch/powerpc/platforms/85xx/cpufreq-jog.c |  388 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/Kconfig            |   11 +
 arch/powerpc/sysdev/fsl_pmc.c             |    3 +
 arch/powerpc/sysdev/fsl_soc.h             |    2 +
 include/linux/cpu.h                       |    4 +
 6 files changed, 409 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/cpufreq-jog.c

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index d154e39..8681a5c 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -4,6 +4,7 @@
 obj-$(CONFIG_SMP) += smp.o
 
 obj-y += common.o sleep.o
+obj-$(CONFIG_MPC85xx_CPUFREQ) += cpufreq-jog.o
 
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/cpufreq-jog.c b/arch/powerpc/platforms/85xx/cpufreq-jog.c
new file mode 100644
index 0000000..ccc0c33
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/cpufreq-jog.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
+ * Author: Dave Liu <daveliu@freescale.com>
+ * Modifier: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * The cpufreq driver is for Freescale 85xx processor,
+ * based on arch/powerpc/platforms/cell/cbe_cpufreq.c
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *	Christian Krafft <krafft@de.ibm.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/of_platform.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/smp.h>
+
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_MUTEX(mpc85xx_switch_mutex);
+static void __iomem *guts;
+
+static u32 sysfreq;
+static unsigned int max_pll[2];
+static atomic_t in_jog_process;
+static struct cpufreq_frequency_table *mpc85xx_freqs;
+static int (*set_pll)(unsigned int cpu, unsigned int pll);
+
+static struct cpufreq_frequency_table mpc8536_freqs_table[] = {
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{7,	0},
+	{8,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table p1022_freqs_table[] = {
+	{2,	0},
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{7,	0},
+	{8,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+#define FREQ_500MHz	500000000
+#define FREQ_800MHz	800000000
+
+#define CORE_RATIO_STRIDE	8
+#define CORE_RATIO_MASK		0x3f
+#define CORE_RATIO_SHIFT	16
+
+#define PORPLLSR	0x0	/* Power-On Reset PLL ratio status register */
+
+#define PMJCR		0x7c	/* Power Management Jog Control Register */
+#define PMJCR_CORE0_SPD	0x00001000
+#define PMJCR_CORE_SPD	0x00002000
+
+#define POWMGTCSR	0x80 /* Power management control and status register */
+#define POWMGTCSR_JOG		0x00200000
+#define POWMGTCSR_INT_MASK	0x00000f00
+
+static void spin_while_jogging(void *dummy)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	atomic_inc(&in_jog_process);
+
+	while (atomic_read(&in_jog_process) != 0)
+		barrier();
+
+	local_irq_restore(flags);
+}
+
+static int get_pll(int hw_cpu)
+{
+	int shift;
+	u32 val = in_be32(guts + PORPLLSR);
+
+	shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+
+	return (val >> shift) & CORE_RATIO_MASK;
+}
+
+static int mpc8536_set_pll(unsigned int cpu, unsigned int pll)
+{
+	u32 corefreq, val, mask;
+	unsigned int cur_pll = get_pll(0);
+	unsigned long flags;
+
+	if (pll == cur_pll)
+		return 0;
+
+	val = (pll & CORE_RATIO_MASK) << CORE_RATIO_SHIFT;
+
+	corefreq = sysfreq * pll / 2;
+	/*
+	 * Set the COREx_SPD bit if the requested core frequency
+	 * is larger than the threshold frequency.
+	 */
+	if (corefreq > FREQ_800MHz)
+			val |= PMJCR_CORE_SPD;
+
+	mask = (CORE_RATIO_MASK << CORE_RATIO_SHIFT) | PMJCR_CORE_SPD;
+	clrsetbits_be32(guts + PMJCR, mask, val);
+
+	/* readback to sync write */
+	in_be32(guts + PMJCR);
+
+	local_irq_save(flags);
+	mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_JOG);
+	local_irq_restore(flags);
+
+	/* verify */
+	cur_pll =  get_pll(0);
+	if (cur_pll != pll) {
+		pr_err("%s: error. The current PLL is %d instead of %d.\n",
+				__func__, cur_pll, pll);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int p1022_set_pll(unsigned int cpu, unsigned int pll)
+{
+	int index, hw_cpu = get_hard_smp_processor_id(cpu);
+	int shift;
+	u32 corefreq, val, mask = 0;
+	unsigned int cur_pll = get_pll(hw_cpu);
+	unsigned long flags;
+	int ret = 0;
+
+	if (pll == cur_pll)
+		return 0;
+
+	shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+	val = (pll & CORE_RATIO_MASK) << shift;
+
+	corefreq = sysfreq * pll / 2;
+	/*
+	 * Set the COREx_SPD bit if the requested core frequency
+	 * is larger than the threshold frequency.
+	 */
+	if (corefreq > FREQ_500MHz)
+		val |= PMJCR_CORE0_SPD << hw_cpu;
+
+	mask = (CORE_RATIO_MASK << shift) | (PMJCR_CORE0_SPD << hw_cpu);
+	clrsetbits_be32(guts + PMJCR, mask, val);
+
+	/* readback to sync write */
+	in_be32(guts + PMJCR);
+
+	cpu_hotplug_disable_before_freeze();
+	/*
+	 * A Jog request can not be asserted when any core is in a low
+	 * power state on P1022. Before executing a jog request, any
+	 * core which is in a low power state must be waked by a
+	 * interrupt, and keep waking up until the sequence is
+	 * finished.
+	 */
+	for_each_present_cpu(index) {
+		if (!cpu_online(index)) {
+			cpu_hotplug_enable_after_thaw();
+			pr_err("%s: error, core%d is down.\n", __func__, index);
+			return -1;
+		}
+	}
+
+	atomic_set(&in_jog_process, 0);
+	smp_call_function(spin_while_jogging, NULL, 0);
+
+	local_irq_save(flags);
+
+	/* Wait for the other core to wake. */
+	if (!spin_event_timeout(atomic_read(&in_jog_process) == 1, 1000, 100)) {
+		pr_err("%s: timeout, the other core is not at running state.\n",
+					__func__);
+		ret = -1;
+		goto err;
+	}
+
+	out_be32(guts + POWMGTCSR, POWMGTCSR_JOG | POWMGTCSR_INT_MASK);
+
+	if (!spin_event_timeout(
+		(in_be32(guts + POWMGTCSR) & POWMGTCSR_JOG) == 0, 1000, 100)) {
+		pr_err("%s: timeout, fail to switch the core frequency.\n",
+				__func__);
+		ret = -1;
+		goto err;
+	}
+
+	clrbits32(guts + POWMGTCSR, POWMGTCSR_INT_MASK);
+	in_be32(guts + POWMGTCSR);
+
+	atomic_set(&in_jog_process, 0);
+err:
+	local_irq_restore(flags);
+	cpu_hotplug_enable_after_thaw();
+
+	/* verify */
+	cur_pll =  get_pll(hw_cpu);
+	if (cur_pll != pll) {
+		pr_err("%s: error, the current PLL of core %d is %d instead of %d.\n",
+				__func__, hw_cpu, cur_pll, pll);
+		return -1;
+	}
+
+	return ret;
+}
+
+/*
+ * cpufreq functions
+ */
+static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned int i, cur_pll;
+	int hw_cpu = get_hard_smp_processor_id(policy->cpu);
+
+	if (!cpu_present(policy->cpu))
+		return -ENODEV;
+
+	/* the latency of a transition, the unit is ns */
+	policy->cpuinfo.transition_latency = 2000;
+
+	cur_pll = get_pll(hw_cpu);
+
+	/* initialize frequency table */
+	pr_debug("core%d frequency table:\n", hw_cpu);
+	for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
+			/* The frequency unit is kHz. */
+			mpc85xx_freqs[i].frequency =
+				(sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
+		} else {
+			mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
+		}
+
+		pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
+
+		if (mpc85xx_freqs[i].index == cur_pll)
+			policy->cur = mpc85xx_freqs[i].frequency;
+	}
+	pr_debug("current pll is at %d, and core freq is%d\n",
+			cur_pll, policy->cur);
+
+	cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
+
+	/*
+	 * This ensures that policy->cpuinfo_min
+	 * and policy->cpuinfo_max are set correctly.
+	 */
+	return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static int mpc85xx_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int new;
+	int ret = 0;
+
+	if (!set_pll)
+		return -ENODEV;
+
+	cpufreq_frequency_table_target(policy,
+				       mpc85xx_freqs,
+				       target_freq,
+				       relation,
+				       &new);
+
+	freqs.old = policy->cur;
+	freqs.new = mpc85xx_freqs[new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock(&mpc85xx_switch_mutex);
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
+	if (!ret) {
+		pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
+			 policy->cpu, mpc85xx_freqs[new].frequency,
+			 mpc85xx_freqs[new].index);
+
+		ppc_proc_freq = freqs.new * 1000ul;
+	}
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&mpc85xx_switch_mutex);
+
+	return ret;
+}
+
+static struct cpufreq_driver mpc85xx_cpufreq_driver = {
+	.verify		= mpc85xx_cpufreq_verify,
+	.target		= mpc85xx_cpufreq_target,
+	.init		= mpc85xx_cpufreq_cpu_init,
+	.exit		= mpc85xx_cpufreq_cpu_exit,
+	.name		= "mpc85xx-JOG",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+};
+
+static struct of_device_id mpc85xx_jog_ids[] = {
+	{ .compatible = "fsl,mpc8536-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{}
+};
+
+int mpc85xx_jog_probe(void)
+{
+	struct device_node *np;
+	unsigned int svr;
+
+	np = of_find_matching_node(NULL, mpc85xx_jog_ids);
+	if (!np)
+		return -ENODEV;
+
+	guts = of_iomap(np, 0);
+	if (!guts) {
+		of_node_put(np);
+		return -ENODEV;
+	}
+
+	sysfreq = fsl_get_sys_freq();
+
+	if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
+		svr = mfspr(SPRN_SVR);
+		if ((svr & 0x7fff) == 0x10) {
+			pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
+			of_node_put(np);
+			return -ENODEV;
+		}
+		mpc85xx_freqs = mpc8536_freqs_table;
+		set_pll = mpc8536_set_pll;
+		max_pll[0] = get_pll(0);
+
+	} else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
+		mpc85xx_freqs = p1022_freqs_table;
+		set_pll = p1022_set_pll;
+		max_pll[0] = get_pll(0);
+		max_pll[1] = get_pll(1);
+	}
+
+	pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
+
+	of_node_put(np);
+	return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
+}
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index a35ca44..7dbd239 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -204,6 +204,17 @@ config CPU_FREQ_PMAC64
 	  This adds support for frequency switching on Apple iMac G5,
 	  and some of the more recent desktop G5 machines as well.
 
+config MPC85xx_CPUFREQ
+	bool "Support for Freescale MPC85xx CPU freq"
+	depends on PPC_85xx && FSL_PMC
+	default n
+	select CPU_FREQ_TABLE
+	help
+	  This adds support for dynamic frequency switching on
+	  Freescale MPC85xx by cpufreq interface. MPC8536 and P1022
+	  have a JOG feature, which provides a dynamic mechanism
+	  to lower or raise the CPU core clock at runtime.
+
 config PPC_PASEMI_CPUFREQ
 	bool "Support for PA Semi PWRficient"
 	depends on PPC_PASEMI
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index b6c8c8f..b809a1b 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -202,6 +202,9 @@ static int pmc_probe(struct platform_device *pdev)
 
 	suspend_set_ops(&pmc_suspend_ops);
 
+#ifdef CONFIG_MPC85xx_CPUFREQ
+	mpc85xx_jog_probe();
+#endif
 	pr_info("Freescale PMC driver: sleep(standby)%s\n",
 		(pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
 	return 0;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index b1510ef..25be25c 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -65,5 +65,7 @@ void fsl_hv_halt(void);
  * code can be compatible with both 32-bit & 36-bit.
  */
 extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
+
+extern int mpc85xx_jog_probe(void);
 #endif
 #endif
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ee28844..eceb399 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -147,6 +147,8 @@ void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
 
+extern void cpu_hotplug_disable_before_freeze(void);
+extern void cpu_hotplug_enable_after_thaw(void);
 #else	/* CONFIG_SMP */
 
 #define cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
@@ -168,6 +170,8 @@ static inline void cpu_maps_update_done(void)
 {
 }
 
+static inline void cpu_hotplug_disable_before_freeze(void)	{}
+static inline void cpu_hotplug_enable_after_thaw(void)	{}
 #endif /* CONFIG_SMP */
 extern struct bus_type cpu_subsys;
 
-- 
1.6.4.1



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

* [PATCH v6 5/5] powerpc/85xx: add support to JOG feature using cpufreq interface
@ 2012-06-26 10:25   ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-26 10:25 UTC (permalink / raw)
  To: linuxppc-dev, scottwood; +Cc: linux-kernel

Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
a dynamic mechanism to lower or raise the CPU core clock at runtime.

This patch adds the support to change CPU frequency using the standard
cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
2:1, 5:2, 3:1, 7:2 and 4:1.

Two CPU cores on P1022 must not in the low power state during the frequency
transition. The driver uses a atomic counter to meet the requirement.

The jog mode frequency transition process on the MPC8536 is similar to
the deep sleep process. The driver need save the CPU state and restore
it after CPU warm reset.

Note:
 * The I/O peripherals such as PCIe and eTSEC may lose packets during
   the jog mode frequency transition.
 * The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
   Subsequent revisions of MPC8536 have corrected the erratum.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v6:
 * changed mpc85xx_jog_probe()
 * call mpc85xx_jog_probe() in arch/powerpc/sysdev/fsl_pmc.c
 * removed changes of kernel/cpu.c

 arch/powerpc/platforms/85xx/Makefile      |    1 +
 arch/powerpc/platforms/85xx/cpufreq-jog.c |  388 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/Kconfig            |   11 +
 arch/powerpc/sysdev/fsl_pmc.c             |    3 +
 arch/powerpc/sysdev/fsl_soc.h             |    2 +
 include/linux/cpu.h                       |    4 +
 6 files changed, 409 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/cpufreq-jog.c

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index d154e39..8681a5c 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -4,6 +4,7 @@
 obj-$(CONFIG_SMP) += smp.o
 
 obj-y += common.o sleep.o
+obj-$(CONFIG_MPC85xx_CPUFREQ) += cpufreq-jog.o
 
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/cpufreq-jog.c b/arch/powerpc/platforms/85xx/cpufreq-jog.c
new file mode 100644
index 0000000..ccc0c33
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/cpufreq-jog.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
+ * Author: Dave Liu <daveliu@freescale.com>
+ * Modifier: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * The cpufreq driver is for Freescale 85xx processor,
+ * based on arch/powerpc/platforms/cell/cbe_cpufreq.c
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *	Christian Krafft <krafft@de.ibm.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/of_platform.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/smp.h>
+
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_MUTEX(mpc85xx_switch_mutex);
+static void __iomem *guts;
+
+static u32 sysfreq;
+static unsigned int max_pll[2];
+static atomic_t in_jog_process;
+static struct cpufreq_frequency_table *mpc85xx_freqs;
+static int (*set_pll)(unsigned int cpu, unsigned int pll);
+
+static struct cpufreq_frequency_table mpc8536_freqs_table[] = {
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{7,	0},
+	{8,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table p1022_freqs_table[] = {
+	{2,	0},
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{7,	0},
+	{8,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+#define FREQ_500MHz	500000000
+#define FREQ_800MHz	800000000
+
+#define CORE_RATIO_STRIDE	8
+#define CORE_RATIO_MASK		0x3f
+#define CORE_RATIO_SHIFT	16
+
+#define PORPLLSR	0x0	/* Power-On Reset PLL ratio status register */
+
+#define PMJCR		0x7c	/* Power Management Jog Control Register */
+#define PMJCR_CORE0_SPD	0x00001000
+#define PMJCR_CORE_SPD	0x00002000
+
+#define POWMGTCSR	0x80 /* Power management control and status register */
+#define POWMGTCSR_JOG		0x00200000
+#define POWMGTCSR_INT_MASK	0x00000f00
+
+static void spin_while_jogging(void *dummy)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	atomic_inc(&in_jog_process);
+
+	while (atomic_read(&in_jog_process) != 0)
+		barrier();
+
+	local_irq_restore(flags);
+}
+
+static int get_pll(int hw_cpu)
+{
+	int shift;
+	u32 val = in_be32(guts + PORPLLSR);
+
+	shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+
+	return (val >> shift) & CORE_RATIO_MASK;
+}
+
+static int mpc8536_set_pll(unsigned int cpu, unsigned int pll)
+{
+	u32 corefreq, val, mask;
+	unsigned int cur_pll = get_pll(0);
+	unsigned long flags;
+
+	if (pll == cur_pll)
+		return 0;
+
+	val = (pll & CORE_RATIO_MASK) << CORE_RATIO_SHIFT;
+
+	corefreq = sysfreq * pll / 2;
+	/*
+	 * Set the COREx_SPD bit if the requested core frequency
+	 * is larger than the threshold frequency.
+	 */
+	if (corefreq > FREQ_800MHz)
+			val |= PMJCR_CORE_SPD;
+
+	mask = (CORE_RATIO_MASK << CORE_RATIO_SHIFT) | PMJCR_CORE_SPD;
+	clrsetbits_be32(guts + PMJCR, mask, val);
+
+	/* readback to sync write */
+	in_be32(guts + PMJCR);
+
+	local_irq_save(flags);
+	mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_JOG);
+	local_irq_restore(flags);
+
+	/* verify */
+	cur_pll =  get_pll(0);
+	if (cur_pll != pll) {
+		pr_err("%s: error. The current PLL is %d instead of %d.\n",
+				__func__, cur_pll, pll);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int p1022_set_pll(unsigned int cpu, unsigned int pll)
+{
+	int index, hw_cpu = get_hard_smp_processor_id(cpu);
+	int shift;
+	u32 corefreq, val, mask = 0;
+	unsigned int cur_pll = get_pll(hw_cpu);
+	unsigned long flags;
+	int ret = 0;
+
+	if (pll == cur_pll)
+		return 0;
+
+	shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+	val = (pll & CORE_RATIO_MASK) << shift;
+
+	corefreq = sysfreq * pll / 2;
+	/*
+	 * Set the COREx_SPD bit if the requested core frequency
+	 * is larger than the threshold frequency.
+	 */
+	if (corefreq > FREQ_500MHz)
+		val |= PMJCR_CORE0_SPD << hw_cpu;
+
+	mask = (CORE_RATIO_MASK << shift) | (PMJCR_CORE0_SPD << hw_cpu);
+	clrsetbits_be32(guts + PMJCR, mask, val);
+
+	/* readback to sync write */
+	in_be32(guts + PMJCR);
+
+	cpu_hotplug_disable_before_freeze();
+	/*
+	 * A Jog request can not be asserted when any core is in a low
+	 * power state on P1022. Before executing a jog request, any
+	 * core which is in a low power state must be waked by a
+	 * interrupt, and keep waking up until the sequence is
+	 * finished.
+	 */
+	for_each_present_cpu(index) {
+		if (!cpu_online(index)) {
+			cpu_hotplug_enable_after_thaw();
+			pr_err("%s: error, core%d is down.\n", __func__, index);
+			return -1;
+		}
+	}
+
+	atomic_set(&in_jog_process, 0);
+	smp_call_function(spin_while_jogging, NULL, 0);
+
+	local_irq_save(flags);
+
+	/* Wait for the other core to wake. */
+	if (!spin_event_timeout(atomic_read(&in_jog_process) == 1, 1000, 100)) {
+		pr_err("%s: timeout, the other core is not at running state.\n",
+					__func__);
+		ret = -1;
+		goto err;
+	}
+
+	out_be32(guts + POWMGTCSR, POWMGTCSR_JOG | POWMGTCSR_INT_MASK);
+
+	if (!spin_event_timeout(
+		(in_be32(guts + POWMGTCSR) & POWMGTCSR_JOG) == 0, 1000, 100)) {
+		pr_err("%s: timeout, fail to switch the core frequency.\n",
+				__func__);
+		ret = -1;
+		goto err;
+	}
+
+	clrbits32(guts + POWMGTCSR, POWMGTCSR_INT_MASK);
+	in_be32(guts + POWMGTCSR);
+
+	atomic_set(&in_jog_process, 0);
+err:
+	local_irq_restore(flags);
+	cpu_hotplug_enable_after_thaw();
+
+	/* verify */
+	cur_pll =  get_pll(hw_cpu);
+	if (cur_pll != pll) {
+		pr_err("%s: error, the current PLL of core %d is %d instead of %d.\n",
+				__func__, hw_cpu, cur_pll, pll);
+		return -1;
+	}
+
+	return ret;
+}
+
+/*
+ * cpufreq functions
+ */
+static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned int i, cur_pll;
+	int hw_cpu = get_hard_smp_processor_id(policy->cpu);
+
+	if (!cpu_present(policy->cpu))
+		return -ENODEV;
+
+	/* the latency of a transition, the unit is ns */
+	policy->cpuinfo.transition_latency = 2000;
+
+	cur_pll = get_pll(hw_cpu);
+
+	/* initialize frequency table */
+	pr_debug("core%d frequency table:\n", hw_cpu);
+	for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
+			/* The frequency unit is kHz. */
+			mpc85xx_freqs[i].frequency =
+				(sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
+		} else {
+			mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
+		}
+
+		pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
+
+		if (mpc85xx_freqs[i].index == cur_pll)
+			policy->cur = mpc85xx_freqs[i].frequency;
+	}
+	pr_debug("current pll is at %d, and core freq is%d\n",
+			cur_pll, policy->cur);
+
+	cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
+
+	/*
+	 * This ensures that policy->cpuinfo_min
+	 * and policy->cpuinfo_max are set correctly.
+	 */
+	return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static int mpc85xx_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int new;
+	int ret = 0;
+
+	if (!set_pll)
+		return -ENODEV;
+
+	cpufreq_frequency_table_target(policy,
+				       mpc85xx_freqs,
+				       target_freq,
+				       relation,
+				       &new);
+
+	freqs.old = policy->cur;
+	freqs.new = mpc85xx_freqs[new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock(&mpc85xx_switch_mutex);
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
+	if (!ret) {
+		pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
+			 policy->cpu, mpc85xx_freqs[new].frequency,
+			 mpc85xx_freqs[new].index);
+
+		ppc_proc_freq = freqs.new * 1000ul;
+	}
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&mpc85xx_switch_mutex);
+
+	return ret;
+}
+
+static struct cpufreq_driver mpc85xx_cpufreq_driver = {
+	.verify		= mpc85xx_cpufreq_verify,
+	.target		= mpc85xx_cpufreq_target,
+	.init		= mpc85xx_cpufreq_cpu_init,
+	.exit		= mpc85xx_cpufreq_cpu_exit,
+	.name		= "mpc85xx-JOG",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+};
+
+static struct of_device_id mpc85xx_jog_ids[] = {
+	{ .compatible = "fsl,mpc8536-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{}
+};
+
+int mpc85xx_jog_probe(void)
+{
+	struct device_node *np;
+	unsigned int svr;
+
+	np = of_find_matching_node(NULL, mpc85xx_jog_ids);
+	if (!np)
+		return -ENODEV;
+
+	guts = of_iomap(np, 0);
+	if (!guts) {
+		of_node_put(np);
+		return -ENODEV;
+	}
+
+	sysfreq = fsl_get_sys_freq();
+
+	if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
+		svr = mfspr(SPRN_SVR);
+		if ((svr & 0x7fff) == 0x10) {
+			pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
+			of_node_put(np);
+			return -ENODEV;
+		}
+		mpc85xx_freqs = mpc8536_freqs_table;
+		set_pll = mpc8536_set_pll;
+		max_pll[0] = get_pll(0);
+
+	} else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
+		mpc85xx_freqs = p1022_freqs_table;
+		set_pll = p1022_set_pll;
+		max_pll[0] = get_pll(0);
+		max_pll[1] = get_pll(1);
+	}
+
+	pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
+
+	of_node_put(np);
+	return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
+}
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index a35ca44..7dbd239 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -204,6 +204,17 @@ config CPU_FREQ_PMAC64
 	  This adds support for frequency switching on Apple iMac G5,
 	  and some of the more recent desktop G5 machines as well.
 
+config MPC85xx_CPUFREQ
+	bool "Support for Freescale MPC85xx CPU freq"
+	depends on PPC_85xx && FSL_PMC
+	default n
+	select CPU_FREQ_TABLE
+	help
+	  This adds support for dynamic frequency switching on
+	  Freescale MPC85xx by cpufreq interface. MPC8536 and P1022
+	  have a JOG feature, which provides a dynamic mechanism
+	  to lower or raise the CPU core clock at runtime.
+
 config PPC_PASEMI_CPUFREQ
 	bool "Support for PA Semi PWRficient"
 	depends on PPC_PASEMI
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index b6c8c8f..b809a1b 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -202,6 +202,9 @@ static int pmc_probe(struct platform_device *pdev)
 
 	suspend_set_ops(&pmc_suspend_ops);
 
+#ifdef CONFIG_MPC85xx_CPUFREQ
+	mpc85xx_jog_probe();
+#endif
 	pr_info("Freescale PMC driver: sleep(standby)%s\n",
 		(pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
 	return 0;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index b1510ef..25be25c 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -65,5 +65,7 @@ void fsl_hv_halt(void);
  * code can be compatible with both 32-bit & 36-bit.
  */
 extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
+
+extern int mpc85xx_jog_probe(void);
 #endif
 #endif
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ee28844..eceb399 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -147,6 +147,8 @@ void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
 
+extern void cpu_hotplug_disable_before_freeze(void);
+extern void cpu_hotplug_enable_after_thaw(void);
 #else	/* CONFIG_SMP */
 
 #define cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
@@ -168,6 +170,8 @@ static inline void cpu_maps_update_done(void)
 {
 }
 
+static inline void cpu_hotplug_disable_before_freeze(void)	{}
+static inline void cpu_hotplug_enable_after_thaw(void)	{}
 #endif /* CONFIG_SMP */
 extern struct bus_type cpu_subsys;
 
-- 
1.6.4.1

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-26 14:03   ` Kumar Gala
  -1 siblings, 0 replies; 50+ messages in thread
From: Kumar Gala @ 2012-06-26 14:03 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli


On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:

> Do hardware timebase sync. Firstly, stop all timebases, and transfer
> the timebase value of the boot core to the other core. Finally,
> start all timebases.
> 
> Only apply to dual-core chips, such as MPC8572, P2020, etc.
> 
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for v6:
> * added 85xx_TB_SYNC
> * added isync() after set_tb()
> * removed extra entries from mpc85xx_smp_guts_ids

Why only on dual-core chips?  Is this because of something related to 2 cores, or related to corenet vs non-corenet SoCs and how turning on/off the timebase works in the SOC?

- k

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-26 14:03   ` Kumar Gala
  0 siblings, 0 replies; 50+ messages in thread
From: Kumar Gala @ 2012-06-26 14:03 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: scottwood, linuxppc-dev, linux-kernel


On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:

> Do hardware timebase sync. Firstly, stop all timebases, and transfer
> the timebase value of the boot core to the other core. Finally,
> start all timebases.
>=20
> Only apply to dual-core chips, such as MPC8572, P2020, etc.
>=20
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for v6:
> * added 85xx_TB_SYNC
> * added isync() after set_tb()
> * removed extra entries from mpc85xx_smp_guts_ids

Why only on dual-core chips?  Is this because of something related to 2 =
cores, or related to corenet vs non-corenet SoCs and how turning on/off =
the timebase works in the SOC?

- k=

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 14:03   ` Kumar Gala
@ 2012-06-26 21:45     ` Scott Wood
  -1 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-26 21:45 UTC (permalink / raw)
  To: Kumar Gala; +Cc: Zhao Chenhui, linuxppc-dev, linux-kernel, leoli

On 06/26/2012 09:03 AM, Kumar Gala wrote:
> 
> On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:
> 
>> Do hardware timebase sync. Firstly, stop all timebases, and transfer
>> the timebase value of the boot core to the other core. Finally,
>> start all timebases.
>>
>> Only apply to dual-core chips, such as MPC8572, P2020, etc.
>>
>> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
>> Signed-off-by: Li Yang <leoli@freescale.com>
>> ---
>> Changes for v6:
>> * added 85xx_TB_SYNC
>> * added isync() after set_tb()
>> * removed extra entries from mpc85xx_smp_guts_ids
> 
> Why only on dual-core chips?  Is this because of something related to
> 2 cores, or related to corenet vs non-corenet SoCs and how turning
> on/off the timebase works in the SOC?

Some parts are due to corenet versus non-corenet, such as the actual
register you write to to disable/enable the timebase.

There's also a two-core assumption in the synchronization code which
I've complained about multiple times -- although on closer inspection it
looks like this is done under cpu_add_remove_lock, and we can assume
that there's only one core at a time in take_timebase(), regardless of
how many cores are in the system.

-Scott


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-26 21:45     ` Scott Wood
  0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-26 21:45 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, Zhao Chenhui, linux-kernel

On 06/26/2012 09:03 AM, Kumar Gala wrote:
> 
> On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:
> 
>> Do hardware timebase sync. Firstly, stop all timebases, and transfer
>> the timebase value of the boot core to the other core. Finally,
>> start all timebases.
>>
>> Only apply to dual-core chips, such as MPC8572, P2020, etc.
>>
>> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
>> Signed-off-by: Li Yang <leoli@freescale.com>
>> ---
>> Changes for v6:
>> * added 85xx_TB_SYNC
>> * added isync() after set_tb()
>> * removed extra entries from mpc85xx_smp_guts_ids
> 
> Why only on dual-core chips?  Is this because of something related to
> 2 cores, or related to corenet vs non-corenet SoCs and how turning
> on/off the timebase works in the SOC?

Some parts are due to corenet versus non-corenet, such as the actual
register you write to to disable/enable the timebase.

There's also a two-core assumption in the synchronization code which
I've complained about multiple times -- although on closer inspection it
looks like this is done under cpu_add_remove_lock, and we can assume
that there's only one core at a time in take_timebase(), regardless of
how many cores are in the system.

-Scott

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 21:45     ` Scott Wood
@ 2012-06-26 22:10       ` Benjamin Herrenschmidt
  -1 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-26 22:10 UTC (permalink / raw)
  To: Scott Wood; +Cc: Kumar Gala, linuxppc-dev, Zhao Chenhui, linux-kernel

On Tue, 2012-06-26 at 16:45 -0500, Scott Wood wrote:

> Some parts are due to corenet versus non-corenet, such as the actual
> register you write to to disable/enable the timebase.
> 
> There's also a two-core assumption in the synchronization code which
> I've complained about multiple times -- although on closer inspection it
> looks like this is done under cpu_add_remove_lock, and we can assume
> that there's only one core at a time in take_timebase(), regardless of
> how many cores are in the system.

Right, it should work fine with any number of cores or am I missing
something ? (btw, since when complaining about something helps ? :-)

Cheers,
Ben.



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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-26 22:10       ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-26 22:10 UTC (permalink / raw)
  To: Scott Wood; +Cc: linux-kernel, linuxppc-dev, Zhao Chenhui

On Tue, 2012-06-26 at 16:45 -0500, Scott Wood wrote:

> Some parts are due to corenet versus non-corenet, such as the actual
> register you write to to disable/enable the timebase.
> 
> There's also a two-core assumption in the synchronization code which
> I've complained about multiple times -- although on closer inspection it
> looks like this is done under cpu_add_remove_lock, and we can assume
> that there's only one core at a time in take_timebase(), regardless of
> how many cores are in the system.

Right, it should work fine with any number of cores or am I missing
something ? (btw, since when complaining about something helps ? :-)

Cheers,
Ben.

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-26 22:10   ` Benjamin Herrenschmidt
  -1 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-26 22:10 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: linuxppc-dev, scottwood, linux-kernel

On Tue, 2012-06-26 at 18:25 +0800, Zhao Chenhui wrote:
> Do hardware timebase sync. Firstly, stop all timebases, and transfer
> the timebase value of the boot core to the other core. Finally,
> start all timebases.
> 
> Only apply to dual-core chips, such as MPC8572, P2020, etc.
> 
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for v6:
>  * added 85xx_TB_SYNC
>  * added isync() after set_tb()
>  * removed extra entries from mpc85xx_smp_guts_ids

What's that CONFIG option for ?

Cheers,
Ben.



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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-26 22:10   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-26 22:10 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: scottwood, linuxppc-dev, linux-kernel

On Tue, 2012-06-26 at 18:25 +0800, Zhao Chenhui wrote:
> Do hardware timebase sync. Firstly, stop all timebases, and transfer
> the timebase value of the boot core to the other core. Finally,
> start all timebases.
> 
> Only apply to dual-core chips, such as MPC8572, P2020, etc.
> 
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for v6:
>  * added 85xx_TB_SYNC
>  * added isync() after set_tb()
>  * removed extra entries from mpc85xx_smp_guts_ids

What's that CONFIG option for ?

Cheers,
Ben.

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 14:03   ` Kumar Gala
@ 2012-06-27 10:10     ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-27 10:10 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli

On Tue, Jun 26, 2012 at 09:03:42AM -0500, Kumar Gala wrote:
> 
> On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:
> 
> > Do hardware timebase sync. Firstly, stop all timebases, and transfer
> > the timebase value of the boot core to the other core. Finally,
> > start all timebases.
> > 
> > Only apply to dual-core chips, such as MPC8572, P2020, etc.
> > 
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > Changes for v6:
> > * added 85xx_TB_SYNC
> > * added isync() after set_tb()
> > * removed extra entries from mpc85xx_smp_guts_ids
> 
> Why only on dual-core chips?  Is this because of something related to 2 cores, or related to corenet vs non-corenet SoCs and how turning on/off the timebase works in the SOC?
> 
> - k

I am working on a timebase sync patch for corenet SoCs which have more than 2 cores.
It is based on this patch.

-Chenhui


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-27 10:10     ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-27 10:10 UTC (permalink / raw)
  To: Kumar Gala; +Cc: scottwood, linuxppc-dev, linux-kernel

On Tue, Jun 26, 2012 at 09:03:42AM -0500, Kumar Gala wrote:
> 
> On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:
> 
> > Do hardware timebase sync. Firstly, stop all timebases, and transfer
> > the timebase value of the boot core to the other core. Finally,
> > start all timebases.
> > 
> > Only apply to dual-core chips, such as MPC8572, P2020, etc.
> > 
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > Changes for v6:
> > * added 85xx_TB_SYNC
> > * added isync() after set_tb()
> > * removed extra entries from mpc85xx_smp_guts_ids
> 
> Why only on dual-core chips?  Is this because of something related to 2 cores, or related to corenet vs non-corenet SoCs and how turning on/off the timebase works in the SOC?
> 
> - k

I am working on a timebase sync patch for corenet SoCs which have more than 2 cores.
It is based on this patch.

-Chenhui

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 22:10   ` Benjamin Herrenschmidt
@ 2012-06-27 10:21     ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-27 10:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli

On Wed, Jun 27, 2012 at 08:10:34AM +1000, Benjamin Herrenschmidt wrote:
> On Tue, 2012-06-26 at 18:25 +0800, Zhao Chenhui wrote:
> > Do hardware timebase sync. Firstly, stop all timebases, and transfer
> > the timebase value of the boot core to the other core. Finally,
> > start all timebases.
> > 
> > Only apply to dual-core chips, such as MPC8572, P2020, etc.
> > 
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > Changes for v6:
> >  * added 85xx_TB_SYNC
> >  * added isync() after set_tb()
> >  * removed extra entries from mpc85xx_smp_guts_ids
> 
> What's that CONFIG option for ?
> 
> Cheers,
> Ben.

This option is to guard the timebase sync routines. It is selected
when KEXEC or HOTPLUG_CPU is enabled on Freescale Book-E platforms.

-Chenhui


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-27 10:21     ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-27 10:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: scottwood, linuxppc-dev, linux-kernel

On Wed, Jun 27, 2012 at 08:10:34AM +1000, Benjamin Herrenschmidt wrote:
> On Tue, 2012-06-26 at 18:25 +0800, Zhao Chenhui wrote:
> > Do hardware timebase sync. Firstly, stop all timebases, and transfer
> > the timebase value of the boot core to the other core. Finally,
> > start all timebases.
> > 
> > Only apply to dual-core chips, such as MPC8572, P2020, etc.
> > 
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > Changes for v6:
> >  * added 85xx_TB_SYNC
> >  * added isync() after set_tb()
> >  * removed extra entries from mpc85xx_smp_guts_ids
> 
> What's that CONFIG option for ?
> 
> Cheers,
> Ben.

This option is to guard the timebase sync routines. It is selected
when KEXEC or HOTPLUG_CPU is enabled on Freescale Book-E platforms.

-Chenhui

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-27 10:21     ` Zhao Chenhui
@ 2012-06-27 11:48       ` Benjamin Herrenschmidt
  -1 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-27 11:48 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli

On Wed, 2012-06-27 at 18:21 +0800, Zhao Chenhui wrote:
> > What's that CONFIG option for ?
> > 
> > Cheers,
> > Ben.
> 
> This option is to guard the timebase sync routines. It is selected
> when KEXEC or HOTPLUG_CPU is enabled on Freescale Book-E platforms.

Any reason not to just make it unconditional ? That sort of config
option tend to just confuse things and make bug reports harder to sort
out.... Also you decrease your test coverage.

Cheers,
Ben.


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-27 11:48       ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-27 11:48 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: scottwood, linuxppc-dev, linux-kernel

On Wed, 2012-06-27 at 18:21 +0800, Zhao Chenhui wrote:
> > What's that CONFIG option for ?
> > 
> > Cheers,
> > Ben.
> 
> This option is to guard the timebase sync routines. It is selected
> when KEXEC or HOTPLUG_CPU is enabled on Freescale Book-E platforms.

Any reason not to just make it unconditional ? That sort of config
option tend to just confuse things and make bug reports harder to sort
out.... Also you decrease your test coverage.

Cheers,
Ben.

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-27 11:48       ` Benjamin Herrenschmidt
@ 2012-06-28  3:38         ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-28  3:38 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli

On Wed, Jun 27, 2012 at 09:48:52PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2012-06-27 at 18:21 +0800, Zhao Chenhui wrote:
> > > What's that CONFIG option for ?
> > > 
> > > Cheers,
> > > Ben.
> > 
> > This option is to guard the timebase sync routines. It is selected
> > when KEXEC or HOTPLUG_CPU is enabled on Freescale Book-E platforms.
> 
> Any reason not to just make it unconditional ? That sort of config
> option tend to just confuse things and make bug reports harder to sort
> out.... Also you decrease your test coverage.
> 
> Cheers,
> Ben.

The bootloader have done a timebase sync. If we do not need KEXEC or HOTPLUG_CPU feature,
it is unnecessary to do it again at boot time of kernel. I only compile the timebase sync routines
when users enable KEXEC or HOTPLUG_CPU.

-Chenhui


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-28  3:38         ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-06-28  3:38 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: scottwood, linuxppc-dev, linux-kernel

On Wed, Jun 27, 2012 at 09:48:52PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2012-06-27 at 18:21 +0800, Zhao Chenhui wrote:
> > > What's that CONFIG option for ?
> > > 
> > > Cheers,
> > > Ben.
> > 
> > This option is to guard the timebase sync routines. It is selected
> > when KEXEC or HOTPLUG_CPU is enabled on Freescale Book-E platforms.
> 
> Any reason not to just make it unconditional ? That sort of config
> option tend to just confuse things and make bug reports harder to sort
> out.... Also you decrease your test coverage.
> 
> Cheers,
> Ben.

The bootloader have done a timebase sync. If we do not need KEXEC or HOTPLUG_CPU feature,
it is unnecessary to do it again at boot time of kernel. I only compile the timebase sync routines
when users enable KEXEC or HOTPLUG_CPU.

-Chenhui

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-28  3:38         ` Zhao Chenhui
@ 2012-06-28 10:50           ` Benjamin Herrenschmidt
  -1 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-28 10:50 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli

On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
> 
> 
> The bootloader have done a timebase sync. If we do not need KEXEC or
> HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
> kernel. I only compile the timebase sync routines
> when users enable KEXEC or HOTPLUG_CPU. 

Still, how much are you really saving ? Is it worth the added mess and
loss of test coverage ?

We have too many conditional stuff like that already.

Cheers,
Ben.



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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-28 10:50           ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 50+ messages in thread
From: Benjamin Herrenschmidt @ 2012-06-28 10:50 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: scottwood, linuxppc-dev, linux-kernel

On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
> 
> 
> The bootloader have done a timebase sync. If we do not need KEXEC or
> HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
> kernel. I only compile the timebase sync routines
> when users enable KEXEC or HOTPLUG_CPU. 

Still, how much are you really saving ? Is it worth the added mess and
loss of test coverage ?

We have too many conditional stuff like that already.

Cheers,
Ben.

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-28 10:50           ` Benjamin Herrenschmidt
@ 2012-06-28 18:30             ` Kumar Gala
  -1 siblings, 0 replies; 50+ messages in thread
From: Kumar Gala @ 2012-06-28 18:30 UTC (permalink / raw)
  To: Zhao Chenhui
  Cc: linuxppc-dev@lists.ozlabs.org list, Scott Wood,
	linux-kernel@vger.kernel.org list, Li Yang,
	Benjamin Herrenschmidt


On Jun 28, 2012, at 5:50 AM, Benjamin Herrenschmidt wrote:

> On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
>> 
>> 
>> The bootloader have done a timebase sync. If we do not need KEXEC or
>> HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
>> kernel. I only compile the timebase sync routines
>> when users enable KEXEC or HOTPLUG_CPU. 
> 
> Still, how much are you really saving ? Is it worth the added mess and
> loss of test coverage ?
> 
> We have too many conditional stuff like that already.
> 
> Cheers,
> Ben.
> 

I'd also be interested to know how long it actually takes to do time base sync this way.  Since you are freezing the timers for some period how long does it really take between the freeze/unfreeze in mpc85xx_give_timebase()

+	mpc85xx_timebase_freeze(1);
...
+	mpc85xx_timebase_freeze(0);

You can use ATBL/U as a way to see # of cycles taken.

- k

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-28 18:30             ` Kumar Gala
  0 siblings, 0 replies; 50+ messages in thread
From: Kumar Gala @ 2012-06-28 18:30 UTC (permalink / raw)
  To: Zhao Chenhui
  Cc: Scott Wood, linuxppc-dev@lists.ozlabs.org list,
	linux-kernel@vger.kernel.org list


On Jun 28, 2012, at 5:50 AM, Benjamin Herrenschmidt wrote:

> On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
>>=20
>>=20
>> The bootloader have done a timebase sync. If we do not need KEXEC or
>> HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
>> kernel. I only compile the timebase sync routines
>> when users enable KEXEC or HOTPLUG_CPU.=20
>=20
> Still, how much are you really saving ? Is it worth the added mess and
> loss of test coverage ?
>=20
> We have too many conditional stuff like that already.
>=20
> Cheers,
> Ben.
>=20

I'd also be interested to know how long it actually takes to do time =
base sync this way.  Since you are freezing the timers for some period =
how long does it really take between the freeze/unfreeze in =
mpc85xx_give_timebase()

+	mpc85xx_timebase_freeze(1);
...
+	mpc85xx_timebase_freeze(0);

You can use ATBL/U as a way to see # of cycles taken.

- k=

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

* RE: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-28 18:30             ` Kumar Gala
@ 2012-06-29 10:33               ` Zhao Chenhui-B35336
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui-B35336 @ 2012-06-29 10:33 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org list,
	linux-kernel@vger.kernel.org list

> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-bounces+chenhui.zhao=freescale.com@lists.ozlabs.org] On Behalf
> Of Kumar Gala
> Sent: Friday, June 29, 2012 2:30 AM
> To: Zhao Chenhui-B35336
> Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org list; linux-kernel@vger.kernel.org list
> Subject: Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
> 
> 
> On Jun 28, 2012, at 5:50 AM, Benjamin Herrenschmidt wrote:
> 
> > On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
> >>
> >>
> >> The bootloader have done a timebase sync. If we do not need KEXEC or
> >> HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
> >> kernel. I only compile the timebase sync routines
> >> when users enable KEXEC or HOTPLUG_CPU.
> >
> > Still, how much are you really saving ? Is it worth the added mess and
> > loss of test coverage ?
> >
> > We have too many conditional stuff like that already.
> >
> > Cheers,
> > Ben.
> >
> 
> I'd also be interested to know how long it actually takes to do time base sync this way.  Since you
> are freezing the timers for some period how long does it really take between the freeze/unfreeze in
> mpc85xx_give_timebase()
> 
> +	mpc85xx_timebase_freeze(1);
> ...
> +	mpc85xx_timebase_freeze(0);
> 
> You can use ATBL/U as a way to see # of cycles taken.
> 
> - k

I measured it using ATBL on MPC8572DS with 1.5GHz core frequency and 600MHz CCB frequency.
The average of 10 times is 1019 clock. It seems that most of the time spent by isync and msync.

-Chenhui


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

* RE: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 10:33               ` Zhao Chenhui-B35336
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui-B35336 @ 2012-06-29 10:33 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org list,
	linux-kernel@vger.kernel.org list

> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-bounces+chenhui.zhao=3Dfreescale.=
com@lists.ozlabs.org] On Behalf
> Of Kumar Gala
> Sent: Friday, June 29, 2012 2:30 AM
> To: Zhao Chenhui-B35336
> Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org list; linux-kernel@v=
ger.kernel.org list
> Subject: Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase syn=
c
>=20
>=20
> On Jun 28, 2012, at 5:50 AM, Benjamin Herrenschmidt wrote:
>=20
> > On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
> >>
> >>
> >> The bootloader have done a timebase sync. If we do not need KEXEC or
> >> HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
> >> kernel. I only compile the timebase sync routines
> >> when users enable KEXEC or HOTPLUG_CPU.
> >
> > Still, how much are you really saving ? Is it worth the added mess and
> > loss of test coverage ?
> >
> > We have too many conditional stuff like that already.
> >
> > Cheers,
> > Ben.
> >
>=20
> I'd also be interested to know how long it actually takes to do time base=
 sync this way.  Since you
> are freezing the timers for some period how long does it really take betw=
een the freeze/unfreeze in
> mpc85xx_give_timebase()
>=20
> +	mpc85xx_timebase_freeze(1);
> ...
> +	mpc85xx_timebase_freeze(0);
>=20
> You can use ATBL/U as a way to see # of cycles taken.
>=20
> - k

I measured it using ATBL on MPC8572DS with 1.5GHz core frequency and 600MHz=
 CCB frequency.
The average of 10 times is 1019 clock. It seems that most of the time spent=
 by isync and msync.

-Chenhui

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-26 10:25 ` Zhao Chenhui
@ 2012-06-29 15:39   ` Tabi Timur-B04825
  -1 siblings, 0 replies; 50+ messages in thread
From: Tabi Timur-B04825 @ 2012-06-29 15:39 UTC (permalink / raw)
  To: Zhao Chenhui-B35336
  Cc: linuxppc-dev, Wood Scott-B07421, linux-kernel, galak, Li Yang-R58472

On Tue, Jun 26, 2012 at 5:25 AM, Zhao Chenhui
<chenhui.zhao@freescale.com> wrote:
> Do hardware timebase sync. Firstly, stop all timebases, and transfer
> the timebase value of the boot core to the other core. Finally,
> start all timebases.
>
> Only apply to dual-core chips, such as MPC8572, P2020, etc.
>
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for v6:
>  * added 85xx_TB_SYNC
>  * added isync() after set_tb()
>  * removed extra entries from mpc85xx_smp_guts_ids
>
>  arch/powerpc/include/asm/fsl_guts.h |    2 +
>  arch/powerpc/platforms/85xx/Kconfig |    5 ++
>  arch/powerpc/platforms/85xx/smp.c   |   84 +++++++++++++++++++++++++++++++++++
>  3 files changed, 91 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
> index aa4c488..dd5ba2c 100644
> --- a/arch/powerpc/include/asm/fsl_guts.h
> +++ b/arch/powerpc/include/asm/fsl_guts.h
> @@ -48,6 +48,8 @@ struct ccsr_guts {
>         __be32  dmuxcr;                /* 0x.0068 - DMA Mux Control Register */
>         u8     res06c[0x70 - 0x6c];
>        __be32  devdisr;        /* 0x.0070 - Device Disable Control */
> +#define CCSR_GUTS_DEVDISR_TB1  0x00001000
> +#define CCSR_GUTS_DEVDISR_TB0  0x00004000
>        __be32  devdisr2;       /* 0x.0074 - Device Disable Control 2 */
>        u8      res078[0x7c - 0x78];
>        __be32  pmjcr;          /* 0x.007c - 4 Power Management Jog Control Register */
> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
> index f000d81..8dd7147 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 85xx_TB_SYNC if KEXEC
>        default y
>
>  if FSL_SOC_BOOKE
> @@ -267,3 +268,7 @@ endif # FSL_SOC_BOOKE
>
>  config TQM85xx
>        bool
> +
> +config 85xx_TB_SYNC
> +       bool
> +       default n
> diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
> index ff42490..edb0cad 100644
> --- a/arch/powerpc/platforms/85xx/smp.c
> +++ b/arch/powerpc/platforms/85xx/smp.c
> @@ -24,6 +24,7 @@
>  #include <asm/mpic.h>
>  #include <asm/cacheflush.h>
>  #include <asm/dbell.h>
> +#include <asm/fsl_guts.h>
>
>  #include <sysdev/fsl_soc.h>
>  #include <sysdev/mpic.h>
> @@ -42,6 +43,69 @@ extern void __early_start(void);
>  #define NUM_BOOT_ENTRY         8
>  #define SIZE_BOOT_ENTRY                (NUM_BOOT_ENTRY * sizeof(u32))
>
> +#ifdef CONFIG_85xx_TB_SYNC
> +static struct ccsr_guts __iomem *guts;
> +static u64 timebase;
> +static int tb_req;
> +static int tb_valid;
> +
> +static void mpc85xx_timebase_freeze(int freeze)
> +{
> +       unsigned int mask;

'mask' should be uint32_t

> +
> +       if (!guts)
> +               return;

This function should never be called if guts is NULL, so this check
should be unnecessary.

> +
> +       mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
> +       if (freeze)
> +               setbits32(&guts->devdisr, mask);
> +       else
> +               clrbits32(&guts->devdisr, mask);
> +
> +       in_be32(&guts->devdisr);
> +}
> +
> +static void mpc85xx_give_timebase(void)
> +{
> +       unsigned long flags;
> +
> +       local_irq_save(flags);
> +
> +       while (!tb_req)
> +               barrier();

I think tb_req and tb_valid need to be 'volatile'.

> +       tb_req = 0;
> +
> +       mpc85xx_timebase_freeze(1);
> +       timebase = get_tb();
> +       mb();
> +       tb_valid = 1;
> +
> +       while (tb_valid)
> +               barrier();
> +
> +       mpc85xx_timebase_freeze(0);
> +
> +       local_irq_restore(flags);
> +}
> +
> +static void mpc85xx_take_timebase(void)
> +{
> +       unsigned long flags;
> +
> +       local_irq_save(flags);
> +
> +       tb_req = 1;
> +       while (!tb_valid)
> +               barrier();
> +
> +       set_tb(timebase >> 32, timebase & 0xffffffff);
> +       isync();
> +       tb_valid = 0;
> +
> +       local_irq_restore(flags);
> +}
> +#endif
> +
>  static int __init
>  smp_85xx_kick_cpu(int nr)
>  {
> @@ -228,6 +292,16 @@ smp_85xx_setup_cpu(int cpu_nr)
>                doorbell_setup_this_cpu();
>  }
>
> +static const struct of_device_id mpc85xx_smp_guts_ids[] = {
> +       { .compatible = "fsl,mpc8572-guts", },
> +       { .compatible = "fsl,p1020-guts", },
> +       { .compatible = "fsl,p1021-guts", },
> +       { .compatible = "fsl,p1022-guts", },
> +       { .compatible = "fsl,p1023-guts", },
> +       { .compatible = "fsl,p2020-guts", },
> +       {},
> +};

I wonder if it's possible to dynamically generate the compatible
string by using the SOC name?

> +
>  void __init mpc85xx_smp_init(void)
>  {
>        struct device_node *np;
> @@ -249,6 +323,16 @@ void __init mpc85xx_smp_init(void)
>                smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
>        }
>
> +       np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
> +       if (np) {
> +#ifdef CONFIG_85xx_TB_SYNC
> +               guts = of_iomap(np, 0);

You need to test the return value of of_iomap().  smp_85xx_ops should
be set only if guts is not NULL.

> +               smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
> +               smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
> +#endif
> +               of_node_put(np);
> +       }
> +
>        smp_ops = &smp_85xx_ops;
>
>  #ifdef CONFIG_KEXEC
> --
> 1.6.4.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



-- 
Timur Tabi
Linux kernel developer at Freescale

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 15:39   ` Tabi Timur-B04825
  0 siblings, 0 replies; 50+ messages in thread
From: Tabi Timur-B04825 @ 2012-06-29 15:39 UTC (permalink / raw)
  To: Zhao Chenhui-B35336
  Cc: Wood Scott-B07421, Li Yang-R58472, linuxppc-dev, linux-kernel

On Tue, Jun 26, 2012 at 5:25 AM, Zhao Chenhui
<chenhui.zhao@freescale.com> wrote:
> Do hardware timebase sync. Firstly, stop all timebases, and transfer
> the timebase value of the boot core to the other core. Finally,
> start all timebases.
>
> Only apply to dual-core chips, such as MPC8572, P2020, etc.
>
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for v6:
> =A0* added 85xx_TB_SYNC
> =A0* added isync() after set_tb()
> =A0* removed extra entries from mpc85xx_smp_guts_ids
>
> =A0arch/powerpc/include/asm/fsl_guts.h | =A0 =A02 +
> =A0arch/powerpc/platforms/85xx/Kconfig | =A0 =A05 ++
> =A0arch/powerpc/platforms/85xx/smp.c =A0 | =A0 84 +++++++++++++++++++++++=
++++++++++++
> =A03 files changed, 91 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/a=
sm/fsl_guts.h
> index aa4c488..dd5ba2c 100644
> --- a/arch/powerpc/include/asm/fsl_guts.h
> +++ b/arch/powerpc/include/asm/fsl_guts.h
> @@ -48,6 +48,8 @@ struct ccsr_guts {
> =A0 =A0 =A0 =A0 __be32 =A0dmuxcr; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* 0x.00=
68 - DMA Mux Control Register */
> =A0 =A0 =A0 =A0 u8 =A0 =A0 res06c[0x70 - 0x6c];
> =A0 =A0 =A0 =A0__be32 =A0devdisr; =A0 =A0 =A0 =A0/* 0x.0070 - Device Disa=
ble Control */
> +#define CCSR_GUTS_DEVDISR_TB1 =A00x00001000
> +#define CCSR_GUTS_DEVDISR_TB0 =A00x00004000
> =A0 =A0 =A0 =A0__be32 =A0devdisr2; =A0 =A0 =A0 /* 0x.0074 - Device Disabl=
e Control 2 */
> =A0 =A0 =A0 =A0u8 =A0 =A0 =A0res078[0x7c - 0x78];
> =A0 =A0 =A0 =A0__be32 =A0pmjcr; =A0 =A0 =A0 =A0 =A0/* 0x.007c - 4 Power M=
anagement Jog Control Register */
> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms=
/85xx/Kconfig
> index f000d81..8dd7147 100644
> --- a/arch/powerpc/platforms/85xx/Kconfig
> +++ b/arch/powerpc/platforms/85xx/Kconfig
> @@ -8,6 +8,7 @@ menuconfig FSL_SOC_BOOKE
> =A0 =A0 =A0 =A0select FSL_PCI if PCI
> =A0 =A0 =A0 =A0select SERIAL_8250_EXTENDED if SERIAL_8250
> =A0 =A0 =A0 =A0select SERIAL_8250_SHARE_IRQ if SERIAL_8250
> + =A0 =A0 =A0 select 85xx_TB_SYNC if KEXEC
> =A0 =A0 =A0 =A0default y
>
> =A0if FSL_SOC_BOOKE
> @@ -267,3 +268,7 @@ endif # FSL_SOC_BOOKE
>
> =A0config TQM85xx
> =A0 =A0 =A0 =A0bool
> +
> +config 85xx_TB_SYNC
> + =A0 =A0 =A0 bool
> + =A0 =A0 =A0 default n
> diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/8=
5xx/smp.c
> index ff42490..edb0cad 100644
> --- a/arch/powerpc/platforms/85xx/smp.c
> +++ b/arch/powerpc/platforms/85xx/smp.c
> @@ -24,6 +24,7 @@
> =A0#include <asm/mpic.h>
> =A0#include <asm/cacheflush.h>
> =A0#include <asm/dbell.h>
> +#include <asm/fsl_guts.h>
>
> =A0#include <sysdev/fsl_soc.h>
> =A0#include <sysdev/mpic.h>
> @@ -42,6 +43,69 @@ extern void __early_start(void);
> =A0#define NUM_BOOT_ENTRY =A0 =A0 =A0 =A0 8
> =A0#define SIZE_BOOT_ENTRY =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(NUM_BOOT_ENTRY=
 * sizeof(u32))
>
> +#ifdef CONFIG_85xx_TB_SYNC
> +static struct ccsr_guts __iomem *guts;
> +static u64 timebase;
> +static int tb_req;
> +static int tb_valid;
> +
> +static void mpc85xx_timebase_freeze(int freeze)
> +{
> + =A0 =A0 =A0 unsigned int mask;

'mask' should be uint32_t

> +
> + =A0 =A0 =A0 if (!guts)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;

This function should never be called if guts is NULL, so this check
should be unnecessary.

> +
> + =A0 =A0 =A0 mask =3D CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
> + =A0 =A0 =A0 if (freeze)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 setbits32(&guts->devdisr, mask);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 clrbits32(&guts->devdisr, mask);
> +
> + =A0 =A0 =A0 in_be32(&guts->devdisr);
> +}
> +
> +static void mpc85xx_give_timebase(void)
> +{
> + =A0 =A0 =A0 unsigned long flags;
> +
> + =A0 =A0 =A0 local_irq_save(flags);
> +
> + =A0 =A0 =A0 while (!tb_req)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 barrier();

I think tb_req and tb_valid need to be 'volatile'.

> + =A0 =A0 =A0 tb_req =3D 0;
> +
> + =A0 =A0 =A0 mpc85xx_timebase_freeze(1);
> + =A0 =A0 =A0 timebase =3D get_tb();
> + =A0 =A0 =A0 mb();
> + =A0 =A0 =A0 tb_valid =3D 1;
> +
> + =A0 =A0 =A0 while (tb_valid)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 barrier();
> +
> + =A0 =A0 =A0 mpc85xx_timebase_freeze(0);
> +
> + =A0 =A0 =A0 local_irq_restore(flags);
> +}
> +
> +static void mpc85xx_take_timebase(void)
> +{
> + =A0 =A0 =A0 unsigned long flags;
> +
> + =A0 =A0 =A0 local_irq_save(flags);
> +
> + =A0 =A0 =A0 tb_req =3D 1;
> + =A0 =A0 =A0 while (!tb_valid)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 barrier();
> +
> + =A0 =A0 =A0 set_tb(timebase >> 32, timebase & 0xffffffff);
> + =A0 =A0 =A0 isync();
> + =A0 =A0 =A0 tb_valid =3D 0;
> +
> + =A0 =A0 =A0 local_irq_restore(flags);
> +}
> +#endif
> +
> =A0static int __init
> =A0smp_85xx_kick_cpu(int nr)
> =A0{
> @@ -228,6 +292,16 @@ smp_85xx_setup_cpu(int cpu_nr)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0doorbell_setup_this_cpu();
> =A0}
>
> +static const struct of_device_id mpc85xx_smp_guts_ids[] =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl,mpc8572-guts", },
> + =A0 =A0 =A0 { .compatible =3D "fsl,p1020-guts", },
> + =A0 =A0 =A0 { .compatible =3D "fsl,p1021-guts", },
> + =A0 =A0 =A0 { .compatible =3D "fsl,p1022-guts", },
> + =A0 =A0 =A0 { .compatible =3D "fsl,p1023-guts", },
> + =A0 =A0 =A0 { .compatible =3D "fsl,p2020-guts", },
> + =A0 =A0 =A0 {},
> +};

I wonder if it's possible to dynamically generate the compatible
string by using the SOC name?

> +
> =A0void __init mpc85xx_smp_init(void)
> =A0{
> =A0 =A0 =A0 =A0struct device_node *np;
> @@ -249,6 +323,16 @@ void __init mpc85xx_smp_init(void)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0smp_85xx_ops.cause_ipi =3D doorbell_cause_=
ipi;
> =A0 =A0 =A0 =A0}
>
> + =A0 =A0 =A0 np =3D of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
> + =A0 =A0 =A0 if (np) {
> +#ifdef CONFIG_85xx_TB_SYNC
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 guts =3D of_iomap(np, 0);

You need to test the return value of of_iomap().  smp_85xx_ops should
be set only if guts is not NULL.

> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 smp_85xx_ops.give_timebase =3D mpc85xx_give=
_timebase;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 smp_85xx_ops.take_timebase =3D mpc85xx_take=
_timebase;
> +#endif
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> + =A0 =A0 =A0 }
> +
> =A0 =A0 =A0 =A0smp_ops =3D &smp_85xx_ops;
>
> =A0#ifdef CONFIG_KEXEC
> --
> 1.6.4.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" i=
n
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at =A0http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at =A0http://www.tux.org/lkml/



--=20
Timur Tabi
Linux kernel developer at Freescale=

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-29 15:39   ` Tabi Timur-B04825
@ 2012-06-29 15:57     ` Scott Wood
  -1 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-29 15:57 UTC (permalink / raw)
  To: Tabi Timur-B04825
  Cc: Zhao Chenhui-B35336, linuxppc-dev, Wood Scott-B07421,
	linux-kernel, galak, Li Yang-R58472

On 06/29/2012 10:39 AM, Tabi Timur-B04825 wrote:
> On Tue, Jun 26, 2012 at 5:25 AM, Zhao Chenhui
> <chenhui.zhao@freescale.com> wrote:
>> +static void mpc85xx_give_timebase(void)
>> +{
>> +       unsigned long flags;
>> +
>> +       local_irq_save(flags);
>> +
>> +       while (!tb_req)
>> +               barrier();
> 
> I think tb_req and tb_valid need to be 'volatile'.

No, barrier() and mb() take care of that.

>> +static const struct of_device_id mpc85xx_smp_guts_ids[] = {
>> +       { .compatible = "fsl,mpc8572-guts", },
>> +       { .compatible = "fsl,p1020-guts", },
>> +       { .compatible = "fsl,p1021-guts", },
>> +       { .compatible = "fsl,p1022-guts", },
>> +       { .compatible = "fsl,p1023-guts", },
>> +       { .compatible = "fsl,p2020-guts", },
>> +       {},
>> +};
> 
> I wonder if it's possible to dynamically generate the compatible
> string by using the SOC name?

Where are you going to get the SoC name from?

-Scott


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 15:57     ` Scott Wood
  0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-29 15:57 UTC (permalink / raw)
  To: Tabi Timur-B04825
  Cc: Wood Scott-B07421, Li Yang-R58472, Zhao Chenhui-B35336,
	linux-kernel, linuxppc-dev

On 06/29/2012 10:39 AM, Tabi Timur-B04825 wrote:
> On Tue, Jun 26, 2012 at 5:25 AM, Zhao Chenhui
> <chenhui.zhao@freescale.com> wrote:
>> +static void mpc85xx_give_timebase(void)
>> +{
>> +       unsigned long flags;
>> +
>> +       local_irq_save(flags);
>> +
>> +       while (!tb_req)
>> +               barrier();
> 
> I think tb_req and tb_valid need to be 'volatile'.

No, barrier() and mb() take care of that.

>> +static const struct of_device_id mpc85xx_smp_guts_ids[] = {
>> +       { .compatible = "fsl,mpc8572-guts", },
>> +       { .compatible = "fsl,p1020-guts", },
>> +       { .compatible = "fsl,p1021-guts", },
>> +       { .compatible = "fsl,p1022-guts", },
>> +       { .compatible = "fsl,p1023-guts", },
>> +       { .compatible = "fsl,p2020-guts", },
>> +       {},
>> +};
> 
> I wonder if it's possible to dynamically generate the compatible
> string by using the SOC name?

Where are you going to get the SoC name from?

-Scott

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-29 15:57     ` Scott Wood
@ 2012-06-29 16:04       ` Timur Tabi
  -1 siblings, 0 replies; 50+ messages in thread
From: Timur Tabi @ 2012-06-29 16:04 UTC (permalink / raw)
  To: Scott Wood
  Cc: Zhao Chenhui-B35336, linuxppc-dev, Wood Scott-B07421,
	linux-kernel, galak, Li Yang-R58472

Scott Wood wrote:

>> I wonder if it's possible to dynamically generate the compatible
>> string by using the SOC name?
> 
> Where are you going to get the SoC name from?

Well, that is why I said "I wonder".   I'm disappointed that the "cpus"
node doesn't help much.  You'd think the name of the CPU would be in the
CPU node somewhere.

-- 
Timur Tabi
Linux kernel developer at Freescale


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 16:04       ` Timur Tabi
  0 siblings, 0 replies; 50+ messages in thread
From: Timur Tabi @ 2012-06-29 16:04 UTC (permalink / raw)
  To: Scott Wood
  Cc: Wood Scott-B07421, Li Yang-R58472, Zhao Chenhui-B35336,
	linux-kernel, linuxppc-dev

Scott Wood wrote:

>> I wonder if it's possible to dynamically generate the compatible
>> string by using the SOC name?
> 
> Where are you going to get the SoC name from?

Well, that is why I said "I wonder".   I'm disappointed that the "cpus"
node doesn't help much.  You'd think the name of the CPU would be in the
CPU node somewhere.

-- 
Timur Tabi
Linux kernel developer at Freescale

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-29 16:04       ` Timur Tabi
@ 2012-06-29 16:10         ` Scott Wood
  -1 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-29 16:10 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Zhao Chenhui-B35336, linuxppc-dev, Wood Scott-B07421,
	linux-kernel, galak, Li Yang-R58472

On 06/29/2012 11:04 AM, Timur Tabi wrote:
> Scott Wood wrote:
> 
>>> I wonder if it's possible to dynamically generate the compatible
>>> string by using the SOC name?
>>
>> Where are you going to get the SoC name from?
> 
> Well, that is why I said "I wonder".   I'm disappointed that the "cpus"
> node doesn't help much.  You'd think the name of the CPU would be in the
> CPU node somewhere.

The SoC is not the CPU.  The CPU is e500v2.

Why is this different from anywhere else where we have a list of
compatibles to match, often based on various SoCs?  Note that we
explicitly want to match only certain SoCs here.

-Scott


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 16:10         ` Scott Wood
  0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-29 16:10 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Wood Scott-B07421, Li Yang-R58472, Zhao Chenhui-B35336,
	linux-kernel, linuxppc-dev

On 06/29/2012 11:04 AM, Timur Tabi wrote:
> Scott Wood wrote:
> 
>>> I wonder if it's possible to dynamically generate the compatible
>>> string by using the SOC name?
>>
>> Where are you going to get the SoC name from?
> 
> Well, that is why I said "I wonder".   I'm disappointed that the "cpus"
> node doesn't help much.  You'd think the name of the CPU would be in the
> CPU node somewhere.

The SoC is not the CPU.  The CPU is e500v2.

Why is this different from anywhere else where we have a list of
compatibles to match, often based on various SoCs?  Note that we
explicitly want to match only certain SoCs here.

-Scott

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-29 16:10         ` Scott Wood
@ 2012-06-29 16:12           ` Timur Tabi
  -1 siblings, 0 replies; 50+ messages in thread
From: Timur Tabi @ 2012-06-29 16:12 UTC (permalink / raw)
  To: Scott Wood
  Cc: Zhao Chenhui-B35336, linuxppc-dev, Wood Scott-B07421,
	linux-kernel, galak, Li Yang-R58472

Scott Wood wrote:
> Why is this different from anywhere else where we have a list of
> compatibles to match, often based on various SoCs?  Note that we
> explicitly want to match only certain SoCs here.

I was just hoping to find a way to avoid an ever increasing list of
compatible strings.  Other posts on this thread imply that this code could
work for all multi-core e500 parts.

-- 
Timur Tabi
Linux kernel developer at Freescale


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 16:12           ` Timur Tabi
  0 siblings, 0 replies; 50+ messages in thread
From: Timur Tabi @ 2012-06-29 16:12 UTC (permalink / raw)
  To: Scott Wood
  Cc: Wood Scott-B07421, Li Yang-R58472, Zhao Chenhui-B35336,
	linux-kernel, linuxppc-dev

Scott Wood wrote:
> Why is this different from anywhere else where we have a list of
> compatibles to match, often based on various SoCs?  Note that we
> explicitly want to match only certain SoCs here.

I was just hoping to find a way to avoid an ever increasing list of
compatible strings.  Other posts on this thread imply that this code could
work for all multi-core e500 parts.

-- 
Timur Tabi
Linux kernel developer at Freescale

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-29 16:12           ` Timur Tabi
@ 2012-06-29 17:10             ` Scott Wood
  -1 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-29 17:10 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Zhao Chenhui-B35336, linuxppc-dev, Wood Scott-B07421,
	linux-kernel, galak, Li Yang-R58472

On 06/29/2012 11:12 AM, Timur Tabi wrote:
> Scott Wood wrote:
>> Why is this different from anywhere else where we have a list of
>> compatibles to match, often based on various SoCs?  Note that we
>> explicitly want to match only certain SoCs here.
> 
> I was just hoping to find a way to avoid an ever increasing list of
> compatible strings. 

PCI drivers have to put up with it, why should we be different? :-)

> Other posts on this thread imply that this code could
> work for all multi-core e500 parts.

That list covers all multi-core e500v2 parts that I know of.  Corenet
based chips will need a slightly different implementation, since the
registers are different.

-Scott


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-06-29 17:10             ` Scott Wood
  0 siblings, 0 replies; 50+ messages in thread
From: Scott Wood @ 2012-06-29 17:10 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Wood Scott-B07421, Li Yang-R58472, Zhao Chenhui-B35336,
	linux-kernel, linuxppc-dev

On 06/29/2012 11:12 AM, Timur Tabi wrote:
> Scott Wood wrote:
>> Why is this different from anywhere else where we have a list of
>> compatibles to match, often based on various SoCs?  Note that we
>> explicitly want to match only certain SoCs here.
> 
> I was just hoping to find a way to avoid an ever increasing list of
> compatible strings. 

PCI drivers have to put up with it, why should we be different? :-)

> Other posts on this thread imply that this code could
> work for all multi-core e500 parts.

That list covers all multi-core e500v2 parts that I know of.  Corenet
based chips will need a slightly different implementation, since the
registers are different.

-Scott

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-29 15:39   ` Tabi Timur-B04825
@ 2012-07-02 10:10     ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-07-02 10:10 UTC (permalink / raw)
  To: Tabi Timur-B04825
  Cc: Zhao Chenhui-B35336, linuxppc-dev, Wood Scott-B07421,
	linux-kernel, galak, Li Yang-R58472, leoli

On Fri, Jun 29, 2012 at 10:39:24AM -0500, Tabi Timur-B04825 wrote:
> On Tue, Jun 26, 2012 at 5:25 AM, Zhao Chenhui
> <chenhui.zhao@freescale.com> wrote:
> > Do hardware timebase sync. Firstly, stop all timebases, and transfer
> > the timebase value of the boot core to the other core. Finally,
> > start all timebases.
> >
> > Only apply to dual-core chips, such as MPC8572, P2020, etc.
> >
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > Changes for v6:
> >  * added 85xx_TB_SYNC
> >  * added isync() after set_tb()
> >  * removed extra entries from mpc85xx_smp_guts_ids
> >
> >  arch/powerpc/include/asm/fsl_guts.h |    2 +
> >  arch/powerpc/platforms/85xx/Kconfig |    5 ++
> >  arch/powerpc/platforms/85xx/smp.c   |   84 +++++++++++++++++++++++++++++++++++
> >  3 files changed, 91 insertions(+), 0 deletions(-)
> >
> > diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
> > index ff42490..edb0cad 100644
> > --- a/arch/powerpc/platforms/85xx/smp.c
> > +++ b/arch/powerpc/platforms/85xx/smp.c
> > @@ -24,6 +24,7 @@
> >  #include <asm/mpic.h>
> >  #include <asm/cacheflush.h>
> >  #include <asm/dbell.h>
> > +#include <asm/fsl_guts.h>
> >
> >  #include <sysdev/fsl_soc.h>
> >  #include <sysdev/mpic.h>
> > @@ -42,6 +43,69 @@ extern void __early_start(void);
> >  #define NUM_BOOT_ENTRY         8
> >  #define SIZE_BOOT_ENTRY                (NUM_BOOT_ENTRY * sizeof(u32))
> >
> > +#ifdef CONFIG_85xx_TB_SYNC
> > +static struct ccsr_guts __iomem *guts;
> > +static u64 timebase;
> > +static int tb_req;
> > +static int tb_valid;
> > +
> > +static void mpc85xx_timebase_freeze(int freeze)
> > +{
> > +       unsigned int mask;
> 
> 'mask' should be uint32_t

OK.

> 
> > +
> > +       if (!guts)
> > +               return;
> 
> This function should never be called if guts is NULL, so this check
> should be unnecessary.

OK.

> 
> > +
> > +       mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
> > +       if (freeze)
> > +               setbits32(&guts->devdisr, mask);
> > +       else
> > +               clrbits32(&guts->devdisr, mask);
> > +
> > +       in_be32(&guts->devdisr);
> > +}
> > +
> > @@ -249,6 +323,16 @@ void __init mpc85xx_smp_init(void)
> >                smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
> >        }
> >
> > +       np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
> > +       if (np) {
> > +#ifdef CONFIG_85xx_TB_SYNC
> > +               guts = of_iomap(np, 0);
> 
> You need to test the return value of of_iomap().  smp_85xx_ops should
> be set only if guts is not NULL.

Yes. Thanks.

> 
> > +               smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
> > +               smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
> > +#endif
> > +               of_node_put(np);
> > +       }
> > +
> >        smp_ops = &smp_85xx_ops;
> >
> >  #ifdef CONFIG_KEXEC
> > --
> > 1.6.4.1


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-07-02 10:10     ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-07-02 10:10 UTC (permalink / raw)
  To: Tabi Timur-B04825
  Cc: Wood Scott-B07421, Li Yang-R58472, Zhao Chenhui-B35336,
	linux-kernel, linuxppc-dev

On Fri, Jun 29, 2012 at 10:39:24AM -0500, Tabi Timur-B04825 wrote:
> On Tue, Jun 26, 2012 at 5:25 AM, Zhao Chenhui
> <chenhui.zhao@freescale.com> wrote:
> > Do hardware timebase sync. Firstly, stop all timebases, and transfer
> > the timebase value of the boot core to the other core. Finally,
> > start all timebases.
> >
> > Only apply to dual-core chips, such as MPC8572, P2020, etc.
> >
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > Changes for v6:
> > =A0* added 85xx_TB_SYNC
> > =A0* added isync() after set_tb()
> > =A0* removed extra entries from mpc85xx_smp_guts_ids
> >
> > =A0arch/powerpc/include/asm/fsl_guts.h | =A0 =A02 +
> > =A0arch/powerpc/platforms/85xx/Kconfig | =A0 =A05 ++
> > =A0arch/powerpc/platforms/85xx/smp.c =A0 | =A0 84 +++++++++++++++++++=
++++++++++++++++
> > =A03 files changed, 91 insertions(+), 0 deletions(-)
> >
> > diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platfor=
ms/85xx/smp.c
> > index ff42490..edb0cad 100644
> > --- a/arch/powerpc/platforms/85xx/smp.c
> > +++ b/arch/powerpc/platforms/85xx/smp.c
> > @@ -24,6 +24,7 @@
> > =A0#include <asm/mpic.h>
> > =A0#include <asm/cacheflush.h>
> > =A0#include <asm/dbell.h>
> > +#include <asm/fsl_guts.h>
> >
> > =A0#include <sysdev/fsl_soc.h>
> > =A0#include <sysdev/mpic.h>
> > @@ -42,6 +43,69 @@ extern void __early_start(void);
> > =A0#define NUM_BOOT_ENTRY =A0 =A0 =A0 =A0 8
> > =A0#define SIZE_BOOT_ENTRY =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(NUM_BOOT_E=
NTRY * sizeof(u32))
> >
> > +#ifdef CONFIG_85xx_TB_SYNC
> > +static struct ccsr_guts __iomem *guts;
> > +static u64 timebase;
> > +static int tb_req;
> > +static int tb_valid;
> > +
> > +static void mpc85xx_timebase_freeze(int freeze)
> > +{
> > + =A0 =A0 =A0 unsigned int mask;
>=20
> 'mask' should be uint32_t

OK.

>=20
> > +
> > + =A0 =A0 =A0 if (!guts)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
>=20
> This function should never be called if guts is NULL, so this check
> should be unnecessary.

OK.

>=20
> > +
> > + =A0 =A0 =A0 mask =3D CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
> > + =A0 =A0 =A0 if (freeze)
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 setbits32(&guts->devdisr, mask);
> > + =A0 =A0 =A0 else
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 clrbits32(&guts->devdisr, mask);
> > +
> > + =A0 =A0 =A0 in_be32(&guts->devdisr);
> > +}
> > +
> > @@ -249,6 +323,16 @@ void __init mpc85xx_smp_init(void)
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0smp_85xx_ops.cause_ipi =3D doorbell_ca=
use_ipi;
> > =A0 =A0 =A0 =A0}
> >
> > + =A0 =A0 =A0 np =3D of_find_matching_node(NULL, mpc85xx_smp_guts_ids=
);
> > + =A0 =A0 =A0 if (np) {
> > +#ifdef CONFIG_85xx_TB_SYNC
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 guts =3D of_iomap(np, 0);
>=20
> You need to test the return value of of_iomap().  smp_85xx_ops should
> be set only if guts is not NULL.

Yes. Thanks.

>=20
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 smp_85xx_ops.give_timebase =3D mpc85xx_=
give_timebase;
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 smp_85xx_ops.take_timebase =3D mpc85xx_=
take_timebase;
> > +#endif
> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> > + =A0 =A0 =A0 }
> > +
> > =A0 =A0 =A0 =A0smp_ops =3D &smp_85xx_ops;
> >
> > =A0#ifdef CONFIG_KEXEC
> > --
> > 1.6.4.1

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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
  2012-06-28 10:50           ` Benjamin Herrenschmidt
@ 2012-07-02 10:44             ` Zhao Chenhui
  -1 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-07-02 10:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli

On Thu, Jun 28, 2012 at 08:50:51PM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
> > 
> > 
> > The bootloader have done a timebase sync. If we do not need KEXEC or
> > HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
> > kernel. I only compile the timebase sync routines
> > when users enable KEXEC or HOTPLUG_CPU. 
> 
> Still, how much are you really saving ? Is it worth the added mess and
> loss of test coverage ?
> 
> We have too many conditional stuff like that already.
> 
> Cheers,
> Ben.

OK. I will remove this config option.

-Chenhui


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

* Re: [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync
@ 2012-07-02 10:44             ` Zhao Chenhui
  0 siblings, 0 replies; 50+ messages in thread
From: Zhao Chenhui @ 2012-07-02 10:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: scottwood, linuxppc-dev, linux-kernel

On Thu, Jun 28, 2012 at 08:50:51PM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2012-06-28 at 11:38 +0800, Zhao Chenhui wrote:
> > 
> > 
> > The bootloader have done a timebase sync. If we do not need KEXEC or
> > HOTPLUG_CPU feature, it is unnecessary to do it again at boot time of
> > kernel. I only compile the timebase sync routines
> > when users enable KEXEC or HOTPLUG_CPU. 
> 
> Still, how much are you really saving ? Is it worth the added mess and
> loss of test coverage ?
> 
> We have too many conditional stuff like that already.
> 
> Cheers,
> Ben.

OK. I will remove this config option.

-Chenhui

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

* Re: [PATCH v6 3/5] powerpc/85xx: add sleep and deep sleep support
  2012-06-26 10:25   ` Zhao Chenhui
@ 2012-07-13 12:27     ` Kumar Gala
  -1 siblings, 0 replies; 50+ messages in thread
From: Kumar Gala @ 2012-07-13 12:27 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: linuxppc-dev, scottwood, linux-kernel, leoli


On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:

> From: Li Yang <leoli@freescale.com>
> 
> In sleep PM mode, the clocks of e500 core and unused IP blocks is
> turned off. IP blocks which are allowed to wake up the processor
> are still running.
> 
> Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode
> in addtion to the sleep PM mode.
> 
> While in deep sleep PM mode, additionally, the power supply is
> removed from e500 core and most IP blocks. Only the blocks needed
> to wake up the chip out of deep sleep are ON.
> 
> This patch supports 32-bit and 36-bit address space.
> 
> The sleep mode is equal to the Standby state in Linux. The deep sleep
> mode is equal to the Suspend-to-RAM state of Linux Power Management.
> 
> Command to enter sleep mode.
>  echo standby > /sys/power/state
> Command to enter deep sleep mode.
>  echo mem > /sys/power/state
> 
> Signed-off-by: Dave Liu <daveliu@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Signed-off-by: Jin Qing <b24347@freescale.com>
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> Cc: Scott Wood <scottwood@freescale.com>
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> ---
> Changes for v6:
> * changed the declaration of flush_dcache_L1()
> * some minor changes
> 
> arch/powerpc/Kconfig                  |    2 +-
> arch/powerpc/include/asm/cacheflush.h |    2 +
> arch/powerpc/kernel/Makefile          |    3 +
> arch/powerpc/kernel/l2cache_85xx.S    |   53 +++
> arch/powerpc/platforms/85xx/Makefile  |    2 +-
> arch/powerpc/platforms/85xx/sleep.S   |  609 +++++++++++++++++++++++++++++++++
> arch/powerpc/sysdev/fsl_pmc.c         |   98 +++++-
> arch/powerpc/sysdev/fsl_soc.h         |    5 +
> 8 files changed, 754 insertions(+), 20 deletions(-)
> create mode 100644 arch/powerpc/kernel/l2cache_85xx.S
> create mode 100644 arch/powerpc/platforms/85xx/sleep.S
> 


> diff --git a/arch/powerpc/kernel/l2cache_85xx.S b/arch/powerpc/kernel/l2cache_85xx.S
> new file mode 100644
> index 0000000..b0b7d1c
> --- /dev/null
> +++ b/arch/powerpc/kernel/l2cache_85xx.S
> @@ -0,0 +1,53 @@
> +/*
> + * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights reserved.
> + *	Scott Wood <scottwood@freescale.com>
> + *	Dave Liu <daveliu@freescale.com>
> + * implement the L2 cache operations of e500 based L2 controller
> + *
> + * 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/reg.h>
> +#include <asm/cputable.h>
> +#include <asm/ppc_asm.h>
> +#include <asm/asm-offsets.h>
> +
> +	.section .text
> +
> +	/* r3 = virtual address of L2 controller, WIMG = 01xx */
> +_GLOBAL(flush_disable_L2)
> +	/* It's a write-through cache, so only invalidation is needed. */
> +	mbar
> +	isync
> +	lwz	r4, 0(r3)
> +	li	r5, 1
> +	rlwimi	r4, r5, 30, 0xc0000000

Can 0xc0000000 be a #define for what I'm guessing is L2E and L2I?

> +	stw	r4, 0(r3)
> +
> +	/* Wait for the invalidate to finish */
> +1:	lwz	r4, 0(r3)
> +	andis.	r4, r4, 0x4000

#define for 0x4000 -> L2I@h

> +	bne	1b
> +	mbar
> +
> +	blr
> +
> +	/* r3 = virtual address of L2 controller, WIMG = 01xx */
> +_GLOBAL(invalidate_enable_L2)
> +	mbar
> +	isync
> +	lwz	r4, 0(r3)
> +	li	r5, 3
> +	rlwimi	r4, r5, 30, 0xc0000000
> +	stw	r4, 0(r3)
> +
> +	/* Wait for the invalidate to finish */
> +1:	lwz	r4, 0(r3)
> +	andis.	r4, r4, 0x4000

same comments as above about #defines.

> +	bne	1b
> +	mbar
> +
> +	blr
> diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> index 2125d4c..d154e39 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -3,7 +3,7 @@
> #
> obj-$(CONFIG_SMP) += smp.o
> 
> -obj-y += common.o
> +obj-y += common.o sleep.o
> 
> obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
> obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
> diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
> new file mode 100644
> index 0000000..b272f0c
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/sleep.S
> @@ -0,0 +1,609 @@
> +/*
> + * Enter and leave deep sleep/sleep state on MPC85xx
> + *
> + * Author: Scott Wood <scottwood@freescale.com>
> + *
> + * Copyright (C) 2006-2012 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + */
> +
> +#include <asm/page.h>
> +#include <asm/ppc_asm.h>
> +#include <asm/reg.h>
> +#include <asm/asm-offsets.h>
> +
> +#define SS_TB		0x00
> +#define SS_HID		0x08 /* 2 HIDs */
> +#define SS_IAC		0x10 /* 2 IACs */
> +#define SS_DAC		0x18 /* 2 DACs */
> +#define SS_DBCR		0x20 /* 3 DBCRs */
> +#define SS_PID		0x2c /* 3 PIDs */
> +#define SS_SPRG		0x38 /* 8 SPRGs */
> +#define SS_IVOR		0x58 /* 20 interrupt vectors */
> +#define SS_TCR		0xa8
> +#define SS_BUCSR	0xac
> +#define SS_L1CSR	0xb0 /* 2 L1CSRs */
> +#define SS_MSR		0xb8
> +#define SS_USPRG	0xbc
> +#define SS_GPREG	0xc0 /* r12-r31 */
> +#define SS_LR		0x110
> +#define SS_CR		0x114
> +#define SS_SP		0x118
> +#define SS_CURRENT	0x11c
> +#define SS_IVPR		0x120
> +#define SS_BPTR		0x124
> +
> +
> +#define STATE_SAVE_SIZE 0x128
> +
> +	.section .data
> +	.align	5
> +mpc85xx_sleep_save_area:
> +	.space	STATE_SAVE_SIZE
> +ccsrbase_low:
> +	.long	0
> +ccsrbase_high:
> +	.long	0
> +powmgtreq:
> +	.long	0
> +
> +	.section .text
> +	.align	12
> +
> +	/*
> +	 * r3 = high word of physical address of CCSR
> +	 * r4 = low word of physical address of CCSR
> +	 * r5 = JOG or deep sleep request
> +	 *      JOG-0x00200000, deep sleep-0x00100000
> +	 */
> +_GLOBAL(mpc85xx_enter_deep_sleep)
> +	lis	r6, ccsrbase_low@ha
> +	stw	r4, ccsrbase_low@l(r6)
> +	lis	r6, ccsrbase_high@ha
> +	stw	r3, ccsrbase_high@l(r6)
> +
> +	lis	r6, powmgtreq@ha
> +	stw	r5, powmgtreq@l(r6)
> +
> +	lis	r10, mpc85xx_sleep_save_area@h
> +	ori	r10, r10, mpc85xx_sleep_save_area@l
> +
> +	mfspr	r5, SPRN_HID0
> +	mfspr	r6, SPRN_HID1
> +
> +	stw	r5, SS_HID+0(r10)
> +	stw	r6, SS_HID+4(r10)
> +
> +	mfspr	r4, SPRN_IAC1
> +	mfspr	r5, SPRN_IAC2
> +	mfspr	r6, SPRN_DAC1
> +	mfspr	r7, SPRN_DAC2
> +
> +	stw	r4, SS_IAC+0(r10)
> +	stw	r5, SS_IAC+4(r10)
> +	stw	r6, SS_DAC+0(r10)
> +	stw	r7, SS_DAC+4(r10)
> +
> +	mfspr	r4, SPRN_DBCR0
> +	mfspr	r5, SPRN_DBCR1
> +	mfspr	r6, SPRN_DBCR2
> +
> +	stw	r4, SS_DBCR+0(r10)
> +	stw	r5, SS_DBCR+4(r10)
> +	stw	r6, SS_DBCR+8(r10)
> +
> +	mfspr	r4, SPRN_PID0
> +	mfspr	r5, SPRN_PID1
> +	mfspr	r6, SPRN_PID2
> +
> +	stw	r4, SS_PID+0(r10)
> +	stw	r5, SS_PID+4(r10)
> +	stw	r6, SS_PID+8(r10)
> +
> +	mfspr	r4, SPRN_SPRG0
> +	mfspr	r5, SPRN_SPRG1
> +	mfspr	r6, SPRN_SPRG2
> +	mfspr	r7, SPRN_SPRG3
> +
> +	stw	r4, SS_SPRG+0x00(r10)
> +	stw	r5, SS_SPRG+0x04(r10)
> +	stw	r6, SS_SPRG+0x08(r10)
> +	stw	r7, SS_SPRG+0x0c(r10)
> +
> +	mfspr	r4, SPRN_SPRG4
> +	mfspr	r5, SPRN_SPRG5
> +	mfspr	r6, SPRN_SPRG6
> +	mfspr	r7, SPRN_SPRG7
> +
> +	stw	r4, SS_SPRG+0x10(r10)
> +	stw	r5, SS_SPRG+0x14(r10)
> +	stw	r6, SS_SPRG+0x18(r10)
> +	stw	r7, SS_SPRG+0x1c(r10)
> +
> +	mfspr	r4, SPRN_IVPR
> +	stw	r4, SS_IVPR(r10)
> +
> +	mfspr	r4, SPRN_IVOR0
> +	mfspr	r5, SPRN_IVOR1
> +	mfspr	r6, SPRN_IVOR2
> +	mfspr	r7, SPRN_IVOR3
> +
> +	stw	r4, SS_IVOR+0x00(r10)
> +	stw	r5, SS_IVOR+0x04(r10)
> +	stw	r6, SS_IVOR+0x08(r10)
> +	stw	r7, SS_IVOR+0x0c(r10)
> +
> +	mfspr	r4, SPRN_IVOR4
> +	mfspr	r5, SPRN_IVOR5
> +	mfspr	r6, SPRN_IVOR6
> +	mfspr	r7, SPRN_IVOR7
> +
> +	stw	r4, SS_IVOR+0x10(r10)
> +	stw	r5, SS_IVOR+0x14(r10)
> +	stw	r6, SS_IVOR+0x18(r10)
> +	stw	r7, SS_IVOR+0x1c(r10)
> +
> +	mfspr	r4, SPRN_IVOR8
> +	mfspr	r5, SPRN_IVOR9
> +	mfspr	r6, SPRN_IVOR10
> +	mfspr	r7, SPRN_IVOR11
> +
> +	stw	r4, SS_IVOR+0x20(r10)
> +	stw	r5, SS_IVOR+0x24(r10)
> +	stw	r6, SS_IVOR+0x28(r10)
> +	stw	r7, SS_IVOR+0x2c(r10)
> +
> +	mfspr	r4, SPRN_IVOR12
> +	mfspr	r5, SPRN_IVOR13
> +	mfspr	r6, SPRN_IVOR14
> +	mfspr	r7, SPRN_IVOR15
> +
> +	stw	r4, SS_IVOR+0x30(r10)
> +	stw	r5, SS_IVOR+0x34(r10)
> +	stw	r6, SS_IVOR+0x38(r10)
> +	stw	r7, SS_IVOR+0x3c(r10)
> +
> +	mfspr	r4, SPRN_IVOR32
> +	mfspr	r5, SPRN_IVOR33
> +	mfspr	r6, SPRN_IVOR34
> +	mfspr	r7, SPRN_IVOR35
> +
> +	stw	r4, SS_IVOR+0x40(r10)
> +	stw	r5, SS_IVOR+0x44(r10)
> +	stw	r6, SS_IVOR+0x48(r10)
> +	stw	r7, SS_IVOR+0x4c(r10)
> +
> +	mfspr	r4, SPRN_TCR
> +	mfspr	r5, SPRN_BUCSR
> +	mfspr	r6, SPRN_L1CSR0
> +	mfspr	r7, SPRN_L1CSR1
> +	mfspr	r8, SPRN_USPRG0
> +
> +	stw	r4, SS_TCR(r10)
> +	stw	r5, SS_BUCSR(r10)
> +	stw	r6, SS_L1CSR+0(r10)
> +	stw	r7, SS_L1CSR+4(r10)
> +	stw	r8, SS_USPRG+0(r10)
> +
> +	stmw	r12, SS_GPREG(r10)
> +
> +	mfmsr	r4
> +	mflr	r5
> +	mfcr	r6
> +
> +	stw	r4, SS_MSR(r10)
> +	stw	r5, SS_LR(r10)
> +	stw	r6, SS_CR(r10)
> +	stw	r1, SS_SP(r10)
> +	stw	r2, SS_CURRENT(r10)
> +
> +1:	mftbu	r4
> +	mftb	r5
> +	mftbu	r6
> +	cmpw	r4, r6
> +	bne	1b
> +
> +	stw	r4, SS_TB+0(r10)
> +	stw	r5, SS_TB+4(r10)
> +
> +	lis	r5, ccsrbase_low@ha
> +	lwz	r4, ccsrbase_low@l(r5)
> +	lis	r5, ccsrbase_high@ha
> +	lwz	r3, ccsrbase_high@l(r5)
> +
> +	/* Disable machine checks and critical exceptions */
> +	mfmsr	r5
> +	rlwinm	r5, r5, 0, ~MSR_CE
> +	rlwinm	r5, r5, 0, ~MSR_ME
> +	mtmsr	r5
> +	isync
> +
> +	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
> +	lis	r5, 0x100f
> +	mtspr	SPRN_MAS0, r5
> +	lis	r5, 0xc000
> +	ori	r5, r5, 0x0500
> +	mtspr	SPRN_MAS1, r5
> +	lis	r5, 0xf000
> +	ori	r5, r5, 0x000a
> +	mtspr	SPRN_MAS2, r5
> +	rlwinm	r5, r4, 0, 0xfffff000
> +	ori	r5, r5, 0x0005

We have #defines that should be used instead of magic numbers for MAS defines/fields.

> +	mtspr	SPRN_MAS3, r5
> +	mtspr	SPRN_MAS7, r3
> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, 0xf000
> +	lwz	r4, 0x20(r3)
> +	stw	r4, SS_BPTR(r10)
> +
> +	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 */
> +	bl	flush_disable_L2
> +	bl	__flush_disable_L1
> +
> +	/* Enable I-cache, so as not to upset the bus
> +	 * with our loop.
> +	 */
> +
> +	mfspr	r4, SPRN_L1CSR1
> +	ori	r4, r4, 1
> +	mtspr	SPRN_L1CSR1, r4
> +	isync
> +
> +	/* Set boot page translation */
> +	lis	r3, 0xf000
> +	lis	r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
> +	ori	r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
> +	rlwinm	r4, r4, 20, 0x000fffff
> +	oris	r4, r4, 0x8000
> +	stw	r4, 0x20(r3)
> +	lwz	r4, 0x20(r3)		/* read-back to flush write */
> +	twi	0, r4, 0
> +	isync
> +
> +	/* Disable the decrementer */
> +	mfspr	r4, SPRN_TCR
> +	rlwinm	r4, r4, 0, ~TCR_DIE
> +	mtspr	SPRN_TCR, r4
> +
> +	mfspr	r4, SPRN_TSR
> +	oris	r4, r4, TSR_DIS@h
> +	mtspr	SPRN_TSR, r4
> +
> +	/* set PMRCCR[VRCNT] to wait power stable for 40ms */
> +	lis	r3, 0xf00e
> +	lwz	r4, 0x84(r3)
> +	clrlwi	r4, r4, 16
> +	oris	r4, r4, 0x12a3
> +	stw	r4, 0x84(r3)
> +	lwz	r4, 0x84(r3)

#defines here for magic numbers?
> +
> +	/* set deep sleep bit in POWMGTSCR */
> +	lis	r3, powmgtreq@ha
> +	lwz	r8, powmgtreq@l(r3)
> +
> +	lis	r3, 0xf00e
> +	lwz	r4, 0x80(r3)
> +	or	r4, r4, r8
> +	stw	r4, 0x80(r3)
> +	lwz	r4, 0x80(r3)		/* read-back to flush write */
> +	twi	0, r4, 0
> +	isync

#defines here for magic numbers?

> +
> +	mftb	r5
> +1:	/* spin until either we enter deep sleep, or the sleep process is
> +	 * aborted due to a pending wakeup event.  Wait some time between
> +	 * accesses, so we don't flood the bus and prevent the pmc from
> +	 * detecting an idle system.
> +	 */
> +
> +	mftb	r4
> +	subf	r7, r5, r4
> +	cmpwi	r7, 1000
> +	blt	1b
> +	mr	r5, r4
> +
> +	lwz	r6, 0x80(r3)
> +	andis.	r6, r6, 0x0010
> +	bne	1b
> +	b	2f

#defines here for magic numbers?

> +
> +2:	mfspr	r4, SPRN_PIR
> +	andi.	r4, r4, 1
> +99:	bne	99b
> +
> +	/* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
> +	lis	r4, 0x1001
> +	mtspr	SPRN_MAS0, r4
> +	lis	r4, 0xc000
> +	ori	r4, r4, 0x0800
> +	mtspr	SPRN_MAS1, r4
> +	li	r4, 0
> +	mtspr	SPRN_MAS2, r4
> +	li	r4, 0x0015
> +	mtspr	SPRN_MAS3, r4
> +	li	r4, 0
> +	mtspr	SPRN_MAS7, r4

Same comment as above about #defines for MAS regs

> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, (3f - PAGE_OFFSET)@h
> +	ori	r3, r3, (3f - PAGE_OFFSET)@l
> +	mtctr	r3
> +	bctr
> +
> +	/* Locate the resume vector in the last word of the current page. */
> +	. = mpc85xx_enter_deep_sleep + 0xffc
> +mpc85xx_deep_resume:
> +	b	2b
> +
> +3:
> +	/* Restore the contents of TLB1[0].  It is assumed that it covers
> +	 * the currently executing code and the sleep save area, and that
> +	 * it does not alias our temporary mapping (which is at virtual zero).
> +	 */
> +	lis	r3, (TLBCAM - PAGE_OFFSET)@h
> +	ori	r3, r3, (TLBCAM - PAGE_OFFSET)@l
> +
> +	lwz	r4, 0(r3)
> +	lwz	r5, 4(r3)
> +	lwz	r6, 8(r3)
> +	lwz	r7, 12(r3)
> +	lwz	r8, 16(r3)
> +
> +	mtspr	SPRN_MAS0, r4
> +	mtspr	SPRN_MAS1, r5
> +	mtspr	SPRN_MAS2, r6
> +	mtspr	SPRN_MAS3, r7
> +	mtspr	SPRN_MAS7, r8
> +
> +	isync
> +	tlbwe
> +	isync
> +
> +	/* Access the ccsrbase address with TLB1[0] */
> +	lis	r5, ccsrbase_low@ha
> +	lwz	r4, ccsrbase_low@l(r5)
> +	lis	r5, ccsrbase_high@ha
> +	lwz	r3, ccsrbase_high@l(r5)
> +
> +	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
> +	lis	r5, 0x100f
> +	mtspr	SPRN_MAS0, r5
> +	lis	r5, 0xc000
> +	ori	r5, r5, 0x0500
> +	mtspr	SPRN_MAS1, r5
> +	lis	r5, 0xf000
> +	ori	r5, r5, 0x000a
> +	mtspr	SPRN_MAS2, r5
> +	rlwinm	r5, r4, 0, 0xfffff000
> +	ori	r5, r5, 0x0005
> +	mtspr	SPRN_MAS3, r5
> +	mtspr	SPRN_MAS7, r3

Same comment as above about #defines for MAS regs

> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 */
> +	bl	invalidate_enable_L2
> +
> +	/* Access the MEM(r10) with TLB1[0] */
> +	lis	r10, mpc85xx_sleep_save_area@h
> +	ori	r10, r10, mpc85xx_sleep_save_area@l
> +
> +	lis	r3, 0xf000
> +	lwz	r4, SS_BPTR(r10)
> +	stw	r4, 0x20(r3)		/* restore BPTR */
> +
> +	/* Program shift running space to PAGE_OFFSET */
> +	mfmsr	r3
> +	lis	r4, 1f@h
> +	ori	r4, r4, 1f@l
> +
> +	mtsrr1	r3
> +	mtsrr0	r4
> +	rfi
> +
> +1:	/* Restore the rest of TLB1, in ascending order so that
> +	 * the TLB1[1] gets invalidated first.
> +	 *
> +	 * XXX: It's better to invalidate the temporary mapping
> +	 * TLB1[15] for CCSR before restore any TLB1 entry include 0.
> +	 */
> +	lis	r4, 0x100f
> +	mtspr	SPRN_MAS0, r4
> +	lis	r4, 0
> +	mtspr	SPRN_MAS1, r4
> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, (TLBCAM + 5*4 - 4)@h
> +	ori	r3, r3, (TLBCAM + 5*4 - 4)@l
> +	li	r4, 15
> +	mtctr	r4
> +
> +2:
> +	lwz	r5, 4(r3)
> +	lwz	r6, 8(r3)
> +	lwz	r7, 12(r3)
> +	lwz	r8, 16(r3)
> +	lwzu	r9, 20(r3)
> +
> +	mtspr	SPRN_MAS0, r5
> +	mtspr	SPRN_MAS1, r6
> +	mtspr	SPRN_MAS2, r7
> +	mtspr	SPRN_MAS3, r8
> +	mtspr	SPRN_MAS7, r9
> +
> +	isync
> +	tlbwe
> +	isync
> +	bdnz	2b
> +
> +	lis	r10, mpc85xx_sleep_save_area@h
> +	ori	r10, r10, mpc85xx_sleep_save_area@l
> +
> +	lwz	r5, SS_HID+0(r10)
> +	lwz	r6, SS_HID+4(r10)
> +
> +	isync
> +	mtspr	SPRN_HID0, r5
> +	isync
> +
> +	msync
> +	mtspr	SPRN_HID1, r6
> +	isync
> +
> +	lwz	r4, SS_IAC+0(r10)
> +	lwz	r5, SS_IAC+4(r10)
> +	lwz	r6, SS_DAC+0(r10)
> +	lwz	r7, SS_DAC+4(r10)
> +
> +	mtspr	SPRN_IAC1, r4
> +	mtspr	SPRN_IAC2, r5
> +	mtspr	SPRN_DAC1, r6
> +	mtspr	SPRN_DAC2, r7
> +
> +	lwz	r4, SS_DBCR+0(r10)
> +	lwz	r5, SS_DBCR+4(r10)
> +	lwz	r6, SS_DBCR+8(r10)
> +
> +	mtspr	SPRN_DBCR0, r4
> +	mtspr	SPRN_DBCR1, r5
> +	mtspr	SPRN_DBCR2, r6
> +
> +	lwz	r4, SS_PID+0(r10)
> +	lwz	r5, SS_PID+4(r10)
> +	lwz	r6, SS_PID+8(r10)
> +
> +	mtspr	SPRN_PID0, r4
> +	mtspr	SPRN_PID1, r5
> +	mtspr	SPRN_PID2, r6
> +
> +	lwz	r4, SS_SPRG+0x00(r10)
> +	lwz	r5, SS_SPRG+0x04(r10)
> +	lwz	r6, SS_SPRG+0x08(r10)
> +	lwz	r7, SS_SPRG+0x0c(r10)
> +
> +	mtspr	SPRN_SPRG0, r4
> +	mtspr	SPRN_SPRG1, r5
> +	mtspr	SPRN_SPRG2, r6
> +	mtspr	SPRN_SPRG3, r7
> +
> +	lwz	r4, SS_SPRG+0x10(r10)
> +	lwz	r5, SS_SPRG+0x14(r10)
> +	lwz	r6, SS_SPRG+0x18(r10)
> +	lwz	r7, SS_SPRG+0x1c(r10)
> +
> +	mtspr	SPRN_SPRG4, r4
> +	mtspr	SPRN_SPRG5, r5
> +	mtspr	SPRN_SPRG6, r6
> +	mtspr	SPRN_SPRG7, r7
> +
> +	lwz	r4, SS_IVPR(r10)
> +	mtspr	SPRN_IVPR, r4
> +
> +	lwz	r4, SS_IVOR+0x00(r10)
> +	lwz	r5, SS_IVOR+0x04(r10)
> +	lwz	r6, SS_IVOR+0x08(r10)
> +	lwz	r7, SS_IVOR+0x0c(r10)
> +
> +	mtspr	SPRN_IVOR0, r4
> +	mtspr	SPRN_IVOR1, r5
> +	mtspr	SPRN_IVOR2, r6
> +	mtspr	SPRN_IVOR3, r7
> +
> +	lwz	r4, SS_IVOR+0x10(r10)
> +	lwz	r5, SS_IVOR+0x14(r10)
> +	lwz	r6, SS_IVOR+0x18(r10)
> +	lwz	r7, SS_IVOR+0x1c(r10)
> +
> +	mtspr	SPRN_IVOR4, r4
> +	mtspr	SPRN_IVOR5, r5
> +	mtspr	SPRN_IVOR6, r6
> +	mtspr	SPRN_IVOR7, r7
> +
> +	lwz	r4, SS_IVOR+0x20(r10)
> +	lwz	r5, SS_IVOR+0x24(r10)
> +	lwz	r6, SS_IVOR+0x28(r10)
> +	lwz	r7, SS_IVOR+0x2c(r10)
> +
> +	mtspr	SPRN_IVOR8, r4
> +	mtspr	SPRN_IVOR9, r5
> +	mtspr	SPRN_IVOR10, r6
> +	mtspr	SPRN_IVOR11, r7
> +
> +	lwz	r4, SS_IVOR+0x30(r10)
> +	lwz	r5, SS_IVOR+0x34(r10)
> +	lwz	r6, SS_IVOR+0x38(r10)
> +	lwz	r7, SS_IVOR+0x3c(r10)
> +
> +	mtspr	SPRN_IVOR12, r4
> +	mtspr	SPRN_IVOR13, r5
> +	mtspr	SPRN_IVOR14, r6
> +	mtspr	SPRN_IVOR15, r7
> +
> +	lwz	r4, SS_IVOR+0x40(r10)
> +	lwz	r5, SS_IVOR+0x44(r10)
> +	lwz	r6, SS_IVOR+0x48(r10)
> +	lwz	r7, SS_IVOR+0x4c(r10)
> +
> +	mtspr	SPRN_IVOR32, r4
> +	mtspr	SPRN_IVOR33, r5
> +	mtspr	SPRN_IVOR34, r6
> +	mtspr	SPRN_IVOR35, r7
> +
> +	lwz	r4, SS_TCR(r10)
> +	lwz	r5, SS_BUCSR(r10)
> +	lwz	r6, SS_L1CSR+0(r10)
> +	lwz	r7, SS_L1CSR+4(r10)
> +	lwz	r8, SS_USPRG+0(r10)
> +
> +	mtspr	SPRN_TCR, r4
> +	mtspr	SPRN_BUCSR, r5
> +
> +	msync
> +	isync
> +	mtspr	SPRN_L1CSR0, r6
> +	isync
> +
> +	mtspr	SPRN_L1CSR1, r7
> +	isync
> +
> +	mtspr	SPRN_USPRG0, r8
> +
> +	lmw	r12, SS_GPREG(r10)
> +
> +	lwz	r1, SS_SP(r10)
> +	lwz	r2, SS_CURRENT(r10)
> +	lwz	r4, SS_MSR(r10)
> +	lwz	r5, SS_LR(r10)
> +	lwz	r6, SS_CR(r10)
> +
> +	msync
> +	mtmsr	r4
> +	isync
> +
> +	mtlr	r5
> +	mtcr	r6
> +
> +	li	r4, 0
> +	mtspr	SPRN_TBWL, r4
> +
> +	lwz	r4, SS_TB+0(r10)
> +	lwz	r5, SS_TB+4(r10)
> +
> +	mtspr	SPRN_TBWU, r4
> +	mtspr	SPRN_TBWL, r5
> +
> +	lis	r3, 1
> +	mtdec	r3
> +
> +	blr




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

* Re: [PATCH v6 3/5] powerpc/85xx: add sleep and deep sleep support
@ 2012-07-13 12:27     ` Kumar Gala
  0 siblings, 0 replies; 50+ messages in thread
From: Kumar Gala @ 2012-07-13 12:27 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: scottwood, linuxppc-dev, linux-kernel


On Jun 26, 2012, at 5:25 AM, Zhao Chenhui wrote:

> From: Li Yang <leoli@freescale.com>
>=20
> In sleep PM mode, the clocks of e500 core and unused IP blocks is
> turned off. IP blocks which are allowed to wake up the processor
> are still running.
>=20
> Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode
> in addtion to the sleep PM mode.
>=20
> While in deep sleep PM mode, additionally, the power supply is
> removed from e500 core and most IP blocks. Only the blocks needed
> to wake up the chip out of deep sleep are ON.
>=20
> This patch supports 32-bit and 36-bit address space.
>=20
> The sleep mode is equal to the Standby state in Linux. The deep sleep
> mode is equal to the Suspend-to-RAM state of Linux Power Management.
>=20
> Command to enter sleep mode.
>  echo standby > /sys/power/state
> Command to enter deep sleep mode.
>  echo mem > /sys/power/state
>=20
> Signed-off-by: Dave Liu <daveliu@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Signed-off-by: Jin Qing <b24347@freescale.com>
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> Cc: Scott Wood <scottwood@freescale.com>
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> ---
> Changes for v6:
> * changed the declaration of flush_dcache_L1()
> * some minor changes
>=20
> arch/powerpc/Kconfig                  |    2 +-
> arch/powerpc/include/asm/cacheflush.h |    2 +
> arch/powerpc/kernel/Makefile          |    3 +
> arch/powerpc/kernel/l2cache_85xx.S    |   53 +++
> arch/powerpc/platforms/85xx/Makefile  |    2 +-
> arch/powerpc/platforms/85xx/sleep.S   |  609 =
+++++++++++++++++++++++++++++++++
> arch/powerpc/sysdev/fsl_pmc.c         |   98 +++++-
> arch/powerpc/sysdev/fsl_soc.h         |    5 +
> 8 files changed, 754 insertions(+), 20 deletions(-)
> create mode 100644 arch/powerpc/kernel/l2cache_85xx.S
> create mode 100644 arch/powerpc/platforms/85xx/sleep.S
>=20


> diff --git a/arch/powerpc/kernel/l2cache_85xx.S =
b/arch/powerpc/kernel/l2cache_85xx.S
> new file mode 100644
> index 0000000..b0b7d1c
> --- /dev/null
> +++ b/arch/powerpc/kernel/l2cache_85xx.S
> @@ -0,0 +1,53 @@
> +/*
> + * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights =
reserved.
> + *	Scott Wood <scottwood@freescale.com>
> + *	Dave Liu <daveliu@freescale.com>
> + * implement the L2 cache operations of e500 based L2 controller
> + *
> + * 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/reg.h>
> +#include <asm/cputable.h>
> +#include <asm/ppc_asm.h>
> +#include <asm/asm-offsets.h>
> +
> +	.section .text
> +
> +	/* r3 =3D virtual address of L2 controller, WIMG =3D 01xx */
> +_GLOBAL(flush_disable_L2)
> +	/* It's a write-through cache, so only invalidation is needed. =
*/
> +	mbar
> +	isync
> +	lwz	r4, 0(r3)
> +	li	r5, 1
> +	rlwimi	r4, r5, 30, 0xc0000000

Can 0xc0000000 be a #define for what I'm guessing is L2E and L2I?

> +	stw	r4, 0(r3)
> +
> +	/* Wait for the invalidate to finish */
> +1:	lwz	r4, 0(r3)
> +	andis.	r4, r4, 0x4000

#define for 0x4000 -> L2I@h

> +	bne	1b
> +	mbar
> +
> +	blr
> +
> +	/* r3 =3D virtual address of L2 controller, WIMG =3D 01xx */
> +_GLOBAL(invalidate_enable_L2)
> +	mbar
> +	isync
> +	lwz	r4, 0(r3)
> +	li	r5, 3
> +	rlwimi	r4, r5, 30, 0xc0000000
> +	stw	r4, 0(r3)
> +
> +	/* Wait for the invalidate to finish */
> +1:	lwz	r4, 0(r3)
> +	andis.	r4, r4, 0x4000

same comments as above about #defines.

> +	bne	1b
> +	mbar
> +
> +	blr
> diff --git a/arch/powerpc/platforms/85xx/Makefile =
b/arch/powerpc/platforms/85xx/Makefile
> index 2125d4c..d154e39 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -3,7 +3,7 @@
> #
> obj-$(CONFIG_SMP) +=3D smp.o
>=20
> -obj-y +=3D common.o
> +obj-y +=3D common.o sleep.o
>=20
> obj-$(CONFIG_MPC8540_ADS) +=3D mpc85xx_ads.o
> obj-$(CONFIG_MPC8560_ADS) +=3D mpc85xx_ads.o
> diff --git a/arch/powerpc/platforms/85xx/sleep.S =
b/arch/powerpc/platforms/85xx/sleep.S
> new file mode 100644
> index 0000000..b272f0c
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/sleep.S
> @@ -0,0 +1,609 @@
> +/*
> + * Enter and leave deep sleep/sleep state on MPC85xx
> + *
> + * Author: Scott Wood <scottwood@freescale.com>
> + *
> + * Copyright (C) 2006-2012 Freescale Semiconductor, Inc. All rights =
reserved.
> + *
> + * This program is free software; you can redistribute it and/or =
modify it
> + * under the terms of the GNU General Public License version 2 as =
published
> + * by the Free Software Foundation.
> + */
> +
> +#include <asm/page.h>
> +#include <asm/ppc_asm.h>
> +#include <asm/reg.h>
> +#include <asm/asm-offsets.h>
> +
> +#define SS_TB		0x00
> +#define SS_HID		0x08 /* 2 HIDs */
> +#define SS_IAC		0x10 /* 2 IACs */
> +#define SS_DAC		0x18 /* 2 DACs */
> +#define SS_DBCR		0x20 /* 3 DBCRs */
> +#define SS_PID		0x2c /* 3 PIDs */
> +#define SS_SPRG		0x38 /* 8 SPRGs */
> +#define SS_IVOR		0x58 /* 20 interrupt vectors */
> +#define SS_TCR		0xa8
> +#define SS_BUCSR	0xac
> +#define SS_L1CSR	0xb0 /* 2 L1CSRs */
> +#define SS_MSR		0xb8
> +#define SS_USPRG	0xbc
> +#define SS_GPREG	0xc0 /* r12-r31 */
> +#define SS_LR		0x110
> +#define SS_CR		0x114
> +#define SS_SP		0x118
> +#define SS_CURRENT	0x11c
> +#define SS_IVPR		0x120
> +#define SS_BPTR		0x124
> +
> +
> +#define STATE_SAVE_SIZE 0x128
> +
> +	.section .data
> +	.align	5
> +mpc85xx_sleep_save_area:
> +	.space	STATE_SAVE_SIZE
> +ccsrbase_low:
> +	.long	0
> +ccsrbase_high:
> +	.long	0
> +powmgtreq:
> +	.long	0
> +
> +	.section .text
> +	.align	12
> +
> +	/*
> +	 * r3 =3D high word of physical address of CCSR
> +	 * r4 =3D low word of physical address of CCSR
> +	 * r5 =3D JOG or deep sleep request
> +	 *      JOG-0x00200000, deep sleep-0x00100000
> +	 */
> +_GLOBAL(mpc85xx_enter_deep_sleep)
> +	lis	r6, ccsrbase_low@ha
> +	stw	r4, ccsrbase_low@l(r6)
> +	lis	r6, ccsrbase_high@ha
> +	stw	r3, ccsrbase_high@l(r6)
> +
> +	lis	r6, powmgtreq@ha
> +	stw	r5, powmgtreq@l(r6)
> +
> +	lis	r10, mpc85xx_sleep_save_area@h
> +	ori	r10, r10, mpc85xx_sleep_save_area@l
> +
> +	mfspr	r5, SPRN_HID0
> +	mfspr	r6, SPRN_HID1
> +
> +	stw	r5, SS_HID+0(r10)
> +	stw	r6, SS_HID+4(r10)
> +
> +	mfspr	r4, SPRN_IAC1
> +	mfspr	r5, SPRN_IAC2
> +	mfspr	r6, SPRN_DAC1
> +	mfspr	r7, SPRN_DAC2
> +
> +	stw	r4, SS_IAC+0(r10)
> +	stw	r5, SS_IAC+4(r10)
> +	stw	r6, SS_DAC+0(r10)
> +	stw	r7, SS_DAC+4(r10)
> +
> +	mfspr	r4, SPRN_DBCR0
> +	mfspr	r5, SPRN_DBCR1
> +	mfspr	r6, SPRN_DBCR2
> +
> +	stw	r4, SS_DBCR+0(r10)
> +	stw	r5, SS_DBCR+4(r10)
> +	stw	r6, SS_DBCR+8(r10)
> +
> +	mfspr	r4, SPRN_PID0
> +	mfspr	r5, SPRN_PID1
> +	mfspr	r6, SPRN_PID2
> +
> +	stw	r4, SS_PID+0(r10)
> +	stw	r5, SS_PID+4(r10)
> +	stw	r6, SS_PID+8(r10)
> +
> +	mfspr	r4, SPRN_SPRG0
> +	mfspr	r5, SPRN_SPRG1
> +	mfspr	r6, SPRN_SPRG2
> +	mfspr	r7, SPRN_SPRG3
> +
> +	stw	r4, SS_SPRG+0x00(r10)
> +	stw	r5, SS_SPRG+0x04(r10)
> +	stw	r6, SS_SPRG+0x08(r10)
> +	stw	r7, SS_SPRG+0x0c(r10)
> +
> +	mfspr	r4, SPRN_SPRG4
> +	mfspr	r5, SPRN_SPRG5
> +	mfspr	r6, SPRN_SPRG6
> +	mfspr	r7, SPRN_SPRG7
> +
> +	stw	r4, SS_SPRG+0x10(r10)
> +	stw	r5, SS_SPRG+0x14(r10)
> +	stw	r6, SS_SPRG+0x18(r10)
> +	stw	r7, SS_SPRG+0x1c(r10)
> +
> +	mfspr	r4, SPRN_IVPR
> +	stw	r4, SS_IVPR(r10)
> +
> +	mfspr	r4, SPRN_IVOR0
> +	mfspr	r5, SPRN_IVOR1
> +	mfspr	r6, SPRN_IVOR2
> +	mfspr	r7, SPRN_IVOR3
> +
> +	stw	r4, SS_IVOR+0x00(r10)
> +	stw	r5, SS_IVOR+0x04(r10)
> +	stw	r6, SS_IVOR+0x08(r10)
> +	stw	r7, SS_IVOR+0x0c(r10)
> +
> +	mfspr	r4, SPRN_IVOR4
> +	mfspr	r5, SPRN_IVOR5
> +	mfspr	r6, SPRN_IVOR6
> +	mfspr	r7, SPRN_IVOR7
> +
> +	stw	r4, SS_IVOR+0x10(r10)
> +	stw	r5, SS_IVOR+0x14(r10)
> +	stw	r6, SS_IVOR+0x18(r10)
> +	stw	r7, SS_IVOR+0x1c(r10)
> +
> +	mfspr	r4, SPRN_IVOR8
> +	mfspr	r5, SPRN_IVOR9
> +	mfspr	r6, SPRN_IVOR10
> +	mfspr	r7, SPRN_IVOR11
> +
> +	stw	r4, SS_IVOR+0x20(r10)
> +	stw	r5, SS_IVOR+0x24(r10)
> +	stw	r6, SS_IVOR+0x28(r10)
> +	stw	r7, SS_IVOR+0x2c(r10)
> +
> +	mfspr	r4, SPRN_IVOR12
> +	mfspr	r5, SPRN_IVOR13
> +	mfspr	r6, SPRN_IVOR14
> +	mfspr	r7, SPRN_IVOR15
> +
> +	stw	r4, SS_IVOR+0x30(r10)
> +	stw	r5, SS_IVOR+0x34(r10)
> +	stw	r6, SS_IVOR+0x38(r10)
> +	stw	r7, SS_IVOR+0x3c(r10)
> +
> +	mfspr	r4, SPRN_IVOR32
> +	mfspr	r5, SPRN_IVOR33
> +	mfspr	r6, SPRN_IVOR34
> +	mfspr	r7, SPRN_IVOR35
> +
> +	stw	r4, SS_IVOR+0x40(r10)
> +	stw	r5, SS_IVOR+0x44(r10)
> +	stw	r6, SS_IVOR+0x48(r10)
> +	stw	r7, SS_IVOR+0x4c(r10)
> +
> +	mfspr	r4, SPRN_TCR
> +	mfspr	r5, SPRN_BUCSR
> +	mfspr	r6, SPRN_L1CSR0
> +	mfspr	r7, SPRN_L1CSR1
> +	mfspr	r8, SPRN_USPRG0
> +
> +	stw	r4, SS_TCR(r10)
> +	stw	r5, SS_BUCSR(r10)
> +	stw	r6, SS_L1CSR+0(r10)
> +	stw	r7, SS_L1CSR+4(r10)
> +	stw	r8, SS_USPRG+0(r10)
> +
> +	stmw	r12, SS_GPREG(r10)
> +
> +	mfmsr	r4
> +	mflr	r5
> +	mfcr	r6
> +
> +	stw	r4, SS_MSR(r10)
> +	stw	r5, SS_LR(r10)
> +	stw	r6, SS_CR(r10)
> +	stw	r1, SS_SP(r10)
> +	stw	r2, SS_CURRENT(r10)
> +
> +1:	mftbu	r4
> +	mftb	r5
> +	mftbu	r6
> +	cmpw	r4, r6
> +	bne	1b
> +
> +	stw	r4, SS_TB+0(r10)
> +	stw	r5, SS_TB+4(r10)
> +
> +	lis	r5, ccsrbase_low@ha
> +	lwz	r4, ccsrbase_low@l(r5)
> +	lis	r5, ccsrbase_high@ha
> +	lwz	r3, ccsrbase_high@l(r5)
> +
> +	/* Disable machine checks and critical exceptions */
> +	mfmsr	r5
> +	rlwinm	r5, r5, 0, ~MSR_CE
> +	rlwinm	r5, r5, 0, ~MSR_ME
> +	mtmsr	r5
> +	isync
> +
> +	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
> +	lis	r5, 0x100f
> +	mtspr	SPRN_MAS0, r5
> +	lis	r5, 0xc000
> +	ori	r5, r5, 0x0500
> +	mtspr	SPRN_MAS1, r5
> +	lis	r5, 0xf000
> +	ori	r5, r5, 0x000a
> +	mtspr	SPRN_MAS2, r5
> +	rlwinm	r5, r4, 0, 0xfffff000
> +	ori	r5, r5, 0x0005

We have #defines that should be used instead of magic numbers for MAS =
defines/fields.

> +	mtspr	SPRN_MAS3, r5
> +	mtspr	SPRN_MAS7, r3
> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, 0xf000
> +	lwz	r4, 0x20(r3)
> +	stw	r4, SS_BPTR(r10)
> +
> +	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 =
*/
> +	bl	flush_disable_L2
> +	bl	__flush_disable_L1
> +
> +	/* Enable I-cache, so as not to upset the bus
> +	 * with our loop.
> +	 */
> +
> +	mfspr	r4, SPRN_L1CSR1
> +	ori	r4, r4, 1
> +	mtspr	SPRN_L1CSR1, r4
> +	isync
> +
> +	/* Set boot page translation */
> +	lis	r3, 0xf000
> +	lis	r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
> +	ori	r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
> +	rlwinm	r4, r4, 20, 0x000fffff
> +	oris	r4, r4, 0x8000
> +	stw	r4, 0x20(r3)
> +	lwz	r4, 0x20(r3)		/* read-back to flush write */
> +	twi	0, r4, 0
> +	isync
> +
> +	/* Disable the decrementer */
> +	mfspr	r4, SPRN_TCR
> +	rlwinm	r4, r4, 0, ~TCR_DIE
> +	mtspr	SPRN_TCR, r4
> +
> +	mfspr	r4, SPRN_TSR
> +	oris	r4, r4, TSR_DIS@h
> +	mtspr	SPRN_TSR, r4
> +
> +	/* set PMRCCR[VRCNT] to wait power stable for 40ms */
> +	lis	r3, 0xf00e
> +	lwz	r4, 0x84(r3)
> +	clrlwi	r4, r4, 16
> +	oris	r4, r4, 0x12a3
> +	stw	r4, 0x84(r3)
> +	lwz	r4, 0x84(r3)

#defines here for magic numbers?
> +
> +	/* set deep sleep bit in POWMGTSCR */
> +	lis	r3, powmgtreq@ha
> +	lwz	r8, powmgtreq@l(r3)
> +
> +	lis	r3, 0xf00e
> +	lwz	r4, 0x80(r3)
> +	or	r4, r4, r8
> +	stw	r4, 0x80(r3)
> +	lwz	r4, 0x80(r3)		/* read-back to flush write */
> +	twi	0, r4, 0
> +	isync

#defines here for magic numbers?

> +
> +	mftb	r5
> +1:	/* spin until either we enter deep sleep, or the sleep process =
is
> +	 * aborted due to a pending wakeup event.  Wait some time =
between
> +	 * accesses, so we don't flood the bus and prevent the pmc from
> +	 * detecting an idle system.
> +	 */
> +
> +	mftb	r4
> +	subf	r7, r5, r4
> +	cmpwi	r7, 1000
> +	blt	1b
> +	mr	r5, r4
> +
> +	lwz	r6, 0x80(r3)
> +	andis.	r6, r6, 0x0010
> +	bne	1b
> +	b	2f

#defines here for magic numbers?

> +
> +2:	mfspr	r4, SPRN_PIR
> +	andi.	r4, r4, 1
> +99:	bne	99b
> +
> +	/* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
> +	lis	r4, 0x1001
> +	mtspr	SPRN_MAS0, r4
> +	lis	r4, 0xc000
> +	ori	r4, r4, 0x0800
> +	mtspr	SPRN_MAS1, r4
> +	li	r4, 0
> +	mtspr	SPRN_MAS2, r4
> +	li	r4, 0x0015
> +	mtspr	SPRN_MAS3, r4
> +	li	r4, 0
> +	mtspr	SPRN_MAS7, r4

Same comment as above about #defines for MAS regs

> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, (3f - PAGE_OFFSET)@h
> +	ori	r3, r3, (3f - PAGE_OFFSET)@l
> +	mtctr	r3
> +	bctr
> +
> +	/* Locate the resume vector in the last word of the current =
page. */
> +	. =3D mpc85xx_enter_deep_sleep + 0xffc
> +mpc85xx_deep_resume:
> +	b	2b
> +
> +3:
> +	/* Restore the contents of TLB1[0].  It is assumed that it =
covers
> +	 * the currently executing code and the sleep save area, and =
that
> +	 * it does not alias our temporary mapping (which is at virtual =
zero).
> +	 */
> +	lis	r3, (TLBCAM - PAGE_OFFSET)@h
> +	ori	r3, r3, (TLBCAM - PAGE_OFFSET)@l
> +
> +	lwz	r4, 0(r3)
> +	lwz	r5, 4(r3)
> +	lwz	r6, 8(r3)
> +	lwz	r7, 12(r3)
> +	lwz	r8, 16(r3)
> +
> +	mtspr	SPRN_MAS0, r4
> +	mtspr	SPRN_MAS1, r5
> +	mtspr	SPRN_MAS2, r6
> +	mtspr	SPRN_MAS3, r7
> +	mtspr	SPRN_MAS7, r8
> +
> +	isync
> +	tlbwe
> +	isync
> +
> +	/* Access the ccsrbase address with TLB1[0] */
> +	lis	r5, ccsrbase_low@ha
> +	lwz	r4, ccsrbase_low@l(r5)
> +	lis	r5, ccsrbase_high@ha
> +	lwz	r3, ccsrbase_high@l(r5)
> +
> +	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
> +	lis	r5, 0x100f
> +	mtspr	SPRN_MAS0, r5
> +	lis	r5, 0xc000
> +	ori	r5, r5, 0x0500
> +	mtspr	SPRN_MAS1, r5
> +	lis	r5, 0xf000
> +	ori	r5, r5, 0x000a
> +	mtspr	SPRN_MAS2, r5
> +	rlwinm	r5, r4, 0, 0xfffff000
> +	ori	r5, r5, 0x0005
> +	mtspr	SPRN_MAS3, r5
> +	mtspr	SPRN_MAS7, r3

Same comment as above about #defines for MAS regs

> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, 0xf002	/* L2 cache controller at CCSR+0x20000 =
*/
> +	bl	invalidate_enable_L2
> +
> +	/* Access the MEM(r10) with TLB1[0] */
> +	lis	r10, mpc85xx_sleep_save_area@h
> +	ori	r10, r10, mpc85xx_sleep_save_area@l
> +
> +	lis	r3, 0xf000
> +	lwz	r4, SS_BPTR(r10)
> +	stw	r4, 0x20(r3)		/* restore BPTR */
> +
> +	/* Program shift running space to PAGE_OFFSET */
> +	mfmsr	r3
> +	lis	r4, 1f@h
> +	ori	r4, r4, 1f@l
> +
> +	mtsrr1	r3
> +	mtsrr0	r4
> +	rfi
> +
> +1:	/* Restore the rest of TLB1, in ascending order so that
> +	 * the TLB1[1] gets invalidated first.
> +	 *
> +	 * XXX: It's better to invalidate the temporary mapping
> +	 * TLB1[15] for CCSR before restore any TLB1 entry include 0.
> +	 */
> +	lis	r4, 0x100f
> +	mtspr	SPRN_MAS0, r4
> +	lis	r4, 0
> +	mtspr	SPRN_MAS1, r4
> +	isync
> +	tlbwe
> +	isync
> +
> +	lis	r3, (TLBCAM + 5*4 - 4)@h
> +	ori	r3, r3, (TLBCAM + 5*4 - 4)@l
> +	li	r4, 15
> +	mtctr	r4
> +
> +2:
> +	lwz	r5, 4(r3)
> +	lwz	r6, 8(r3)
> +	lwz	r7, 12(r3)
> +	lwz	r8, 16(r3)
> +	lwzu	r9, 20(r3)
> +
> +	mtspr	SPRN_MAS0, r5
> +	mtspr	SPRN_MAS1, r6
> +	mtspr	SPRN_MAS2, r7
> +	mtspr	SPRN_MAS3, r8
> +	mtspr	SPRN_MAS7, r9
> +
> +	isync
> +	tlbwe
> +	isync
> +	bdnz	2b
> +
> +	lis	r10, mpc85xx_sleep_save_area@h
> +	ori	r10, r10, mpc85xx_sleep_save_area@l
> +
> +	lwz	r5, SS_HID+0(r10)
> +	lwz	r6, SS_HID+4(r10)
> +
> +	isync
> +	mtspr	SPRN_HID0, r5
> +	isync
> +
> +	msync
> +	mtspr	SPRN_HID1, r6
> +	isync
> +
> +	lwz	r4, SS_IAC+0(r10)
> +	lwz	r5, SS_IAC+4(r10)
> +	lwz	r6, SS_DAC+0(r10)
> +	lwz	r7, SS_DAC+4(r10)
> +
> +	mtspr	SPRN_IAC1, r4
> +	mtspr	SPRN_IAC2, r5
> +	mtspr	SPRN_DAC1, r6
> +	mtspr	SPRN_DAC2, r7
> +
> +	lwz	r4, SS_DBCR+0(r10)
> +	lwz	r5, SS_DBCR+4(r10)
> +	lwz	r6, SS_DBCR+8(r10)
> +
> +	mtspr	SPRN_DBCR0, r4
> +	mtspr	SPRN_DBCR1, r5
> +	mtspr	SPRN_DBCR2, r6
> +
> +	lwz	r4, SS_PID+0(r10)
> +	lwz	r5, SS_PID+4(r10)
> +	lwz	r6, SS_PID+8(r10)
> +
> +	mtspr	SPRN_PID0, r4
> +	mtspr	SPRN_PID1, r5
> +	mtspr	SPRN_PID2, r6
> +
> +	lwz	r4, SS_SPRG+0x00(r10)
> +	lwz	r5, SS_SPRG+0x04(r10)
> +	lwz	r6, SS_SPRG+0x08(r10)
> +	lwz	r7, SS_SPRG+0x0c(r10)
> +
> +	mtspr	SPRN_SPRG0, r4
> +	mtspr	SPRN_SPRG1, r5
> +	mtspr	SPRN_SPRG2, r6
> +	mtspr	SPRN_SPRG3, r7
> +
> +	lwz	r4, SS_SPRG+0x10(r10)
> +	lwz	r5, SS_SPRG+0x14(r10)
> +	lwz	r6, SS_SPRG+0x18(r10)
> +	lwz	r7, SS_SPRG+0x1c(r10)
> +
> +	mtspr	SPRN_SPRG4, r4
> +	mtspr	SPRN_SPRG5, r5
> +	mtspr	SPRN_SPRG6, r6
> +	mtspr	SPRN_SPRG7, r7
> +
> +	lwz	r4, SS_IVPR(r10)
> +	mtspr	SPRN_IVPR, r4
> +
> +	lwz	r4, SS_IVOR+0x00(r10)
> +	lwz	r5, SS_IVOR+0x04(r10)
> +	lwz	r6, SS_IVOR+0x08(r10)
> +	lwz	r7, SS_IVOR+0x0c(r10)
> +
> +	mtspr	SPRN_IVOR0, r4
> +	mtspr	SPRN_IVOR1, r5
> +	mtspr	SPRN_IVOR2, r6
> +	mtspr	SPRN_IVOR3, r7
> +
> +	lwz	r4, SS_IVOR+0x10(r10)
> +	lwz	r5, SS_IVOR+0x14(r10)
> +	lwz	r6, SS_IVOR+0x18(r10)
> +	lwz	r7, SS_IVOR+0x1c(r10)
> +
> +	mtspr	SPRN_IVOR4, r4
> +	mtspr	SPRN_IVOR5, r5
> +	mtspr	SPRN_IVOR6, r6
> +	mtspr	SPRN_IVOR7, r7
> +
> +	lwz	r4, SS_IVOR+0x20(r10)
> +	lwz	r5, SS_IVOR+0x24(r10)
> +	lwz	r6, SS_IVOR+0x28(r10)
> +	lwz	r7, SS_IVOR+0x2c(r10)
> +
> +	mtspr	SPRN_IVOR8, r4
> +	mtspr	SPRN_IVOR9, r5
> +	mtspr	SPRN_IVOR10, r6
> +	mtspr	SPRN_IVOR11, r7
> +
> +	lwz	r4, SS_IVOR+0x30(r10)
> +	lwz	r5, SS_IVOR+0x34(r10)
> +	lwz	r6, SS_IVOR+0x38(r10)
> +	lwz	r7, SS_IVOR+0x3c(r10)
> +
> +	mtspr	SPRN_IVOR12, r4
> +	mtspr	SPRN_IVOR13, r5
> +	mtspr	SPRN_IVOR14, r6
> +	mtspr	SPRN_IVOR15, r7
> +
> +	lwz	r4, SS_IVOR+0x40(r10)
> +	lwz	r5, SS_IVOR+0x44(r10)
> +	lwz	r6, SS_IVOR+0x48(r10)
> +	lwz	r7, SS_IVOR+0x4c(r10)
> +
> +	mtspr	SPRN_IVOR32, r4
> +	mtspr	SPRN_IVOR33, r5
> +	mtspr	SPRN_IVOR34, r6
> +	mtspr	SPRN_IVOR35, r7
> +
> +	lwz	r4, SS_TCR(r10)
> +	lwz	r5, SS_BUCSR(r10)
> +	lwz	r6, SS_L1CSR+0(r10)
> +	lwz	r7, SS_L1CSR+4(r10)
> +	lwz	r8, SS_USPRG+0(r10)
> +
> +	mtspr	SPRN_TCR, r4
> +	mtspr	SPRN_BUCSR, r5
> +
> +	msync
> +	isync
> +	mtspr	SPRN_L1CSR0, r6
> +	isync
> +
> +	mtspr	SPRN_L1CSR1, r7
> +	isync
> +
> +	mtspr	SPRN_USPRG0, r8
> +
> +	lmw	r12, SS_GPREG(r10)
> +
> +	lwz	r1, SS_SP(r10)
> +	lwz	r2, SS_CURRENT(r10)
> +	lwz	r4, SS_MSR(r10)
> +	lwz	r5, SS_LR(r10)
> +	lwz	r6, SS_CR(r10)
> +
> +	msync
> +	mtmsr	r4
> +	isync
> +
> +	mtlr	r5
> +	mtcr	r6
> +
> +	li	r4, 0
> +	mtspr	SPRN_TBWL, r4
> +
> +	lwz	r4, SS_TB+0(r10)
> +	lwz	r5, SS_TB+4(r10)
> +
> +	mtspr	SPRN_TBWU, r4
> +	mtspr	SPRN_TBWL, r5
> +
> +	lis	r3, 1
> +	mtdec	r3
> +
> +	blr

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

end of thread, other threads:[~2012-07-13 12:27 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-26 10:25 [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync Zhao Chenhui
2012-06-26 10:25 ` Zhao Chenhui
2012-06-26 10:25 ` [PATCH v6 2/5] powerpc/85xx: add HOTPLUG_CPU support Zhao Chenhui
2012-06-26 10:25   ` Zhao Chenhui
2012-06-26 10:25 ` [PATCH v6 3/5] powerpc/85xx: add sleep and deep sleep support Zhao Chenhui
2012-06-26 10:25   ` Zhao Chenhui
2012-07-13 12:27   ` Kumar Gala
2012-07-13 12:27     ` Kumar Gala
2012-06-26 10:25 ` [PATCH v6 4/5] fsl_pmc: Add API to enable device as wakeup event source Zhao Chenhui
2012-06-26 10:25   ` Zhao Chenhui
2012-06-26 10:25 ` [PATCH v6 5/5] powerpc/85xx: add support to JOG feature using cpufreq interface Zhao Chenhui
2012-06-26 10:25   ` Zhao Chenhui
2012-06-26 14:03 ` [PATCH v6 1/5] powerpc/85xx: implement hardware timebase sync Kumar Gala
2012-06-26 14:03   ` Kumar Gala
2012-06-26 21:45   ` Scott Wood
2012-06-26 21:45     ` Scott Wood
2012-06-26 22:10     ` Benjamin Herrenschmidt
2012-06-26 22:10       ` Benjamin Herrenschmidt
2012-06-27 10:10   ` Zhao Chenhui
2012-06-27 10:10     ` Zhao Chenhui
2012-06-26 22:10 ` Benjamin Herrenschmidt
2012-06-26 22:10   ` Benjamin Herrenschmidt
2012-06-27 10:21   ` Zhao Chenhui
2012-06-27 10:21     ` Zhao Chenhui
2012-06-27 11:48     ` Benjamin Herrenschmidt
2012-06-27 11:48       ` Benjamin Herrenschmidt
2012-06-28  3:38       ` Zhao Chenhui
2012-06-28  3:38         ` Zhao Chenhui
2012-06-28 10:50         ` Benjamin Herrenschmidt
2012-06-28 10:50           ` Benjamin Herrenschmidt
2012-06-28 18:30           ` Kumar Gala
2012-06-28 18:30             ` Kumar Gala
2012-06-29 10:33             ` Zhao Chenhui-B35336
2012-06-29 10:33               ` Zhao Chenhui-B35336
2012-07-02 10:44           ` Zhao Chenhui
2012-07-02 10:44             ` Zhao Chenhui
2012-06-29 15:39 ` Tabi Timur-B04825
2012-06-29 15:39   ` Tabi Timur-B04825
2012-06-29 15:57   ` Scott Wood
2012-06-29 15:57     ` Scott Wood
2012-06-29 16:04     ` Timur Tabi
2012-06-29 16:04       ` Timur Tabi
2012-06-29 16:10       ` Scott Wood
2012-06-29 16:10         ` Scott Wood
2012-06-29 16:12         ` Timur Tabi
2012-06-29 16:12           ` Timur Tabi
2012-06-29 17:10           ` Scott Wood
2012-06-29 17:10             ` Scott Wood
2012-07-02 10:10   ` Zhao Chenhui
2012-07-02 10:10     ` Zhao Chenhui

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.