aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2008-06-18 17:26:52 -0400
committerKumar Gala <galak@kernel.crashing.org>2008-06-26 02:48:56 -0400
commitfc4033b2f8b1482022bff3d05505a1b1631bb6de (patch)
treec84b275968011911d8c96acebe89aa2dd92323bf
parent3dfa8773674e16f95f70a0e631e80c69390d04d7 (diff)
powerpc/85xx: add DOZE/NAP support for e500 core
The e500 core enter DOZE/NAP power-saving modes when the core go to cpu_idle routine. The power management default running mode is DOZE, If the user echo 1 > /proc/sys/kernel/powersave-nap the system will change to NAP running mode. Signed-off-by: Dave Liu <daveliu@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r--arch/powerpc/kernel/Makefile1
-rw-r--r--arch/powerpc/kernel/cputable.c3
-rw-r--r--arch/powerpc/kernel/entry_32.S8
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S47
-rw-r--r--arch/powerpc/kernel/idle_6xx.S2
-rw-r--r--arch/powerpc/kernel/idle_e500.S84
-rw-r--r--arch/powerpc/kernel/setup_32.c5
-rw-r--r--include/asm-powerpc/cputable.h11
-rw-r--r--include/asm-powerpc/machdep.h1
-rw-r--r--include/asm-powerpc/reg.h2
-rw-r--r--include/asm-powerpc/reg_booke.h2
11 files changed, 152 insertions, 14 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 2346d271fbfd..0e8f928fef70 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_IBMVIO) += vio.o
38obj-$(CONFIG_IBMEBUS) += ibmebus.o 38obj-$(CONFIG_IBMEBUS) += ibmebus.o
39obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o 39obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
40obj-$(CONFIG_CRASH_DUMP) += crash_dump.o 40obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
41obj-$(CONFIG_E500) += idle_e500.o
41obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o 42obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
42obj-$(CONFIG_TAU) += tau_6xx.o 43obj-$(CONFIG_TAU) += tau_6xx.o
43obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ 44obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index aa421f5651c8..c5397c11ae91 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1491,7 +1491,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
1491 .pvr_mask = 0xffff0000, 1491 .pvr_mask = 0xffff0000,
1492 .pvr_value = 0x80200000, 1492 .pvr_value = 0x80200000,
1493 .cpu_name = "e500", 1493 .cpu_name = "e500",
1494 /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
1495 .cpu_features = CPU_FTRS_E500, 1494 .cpu_features = CPU_FTRS_E500,
1496 .cpu_user_features = COMMON_USER_BOOKE | 1495 .cpu_user_features = COMMON_USER_BOOKE |
1497 PPC_FEATURE_HAS_SPE_COMP | 1496 PPC_FEATURE_HAS_SPE_COMP |
@@ -1508,7 +1507,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
1508 .pvr_mask = 0xffff0000, 1507 .pvr_mask = 0xffff0000,
1509 .pvr_value = 0x80210000, 1508 .pvr_value = 0x80210000,
1510 .cpu_name = "e500v2", 1509 .cpu_name = "e500v2",
1511 /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
1512 .cpu_features = CPU_FTRS_E500_2, 1510 .cpu_features = CPU_FTRS_E500_2,
1513 .cpu_user_features = COMMON_USER_BOOKE | 1511 .cpu_user_features = COMMON_USER_BOOKE |
1514 PPC_FEATURE_HAS_SPE_COMP | 1512 PPC_FEATURE_HAS_SPE_COMP |
@@ -1526,7 +1524,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
1526 .pvr_mask = 0xffff0000, 1524 .pvr_mask = 0xffff0000,
1527 .pvr_value = 0x80230000, 1525 .pvr_value = 0x80230000,
1528 .cpu_name = "e500mc", 1526 .cpu_name = "e500mc",
1529 /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
1530 .cpu_features = CPU_FTRS_E500MC, 1527 .cpu_features = CPU_FTRS_E500MC,
1531 .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, 1528 .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
1532 .icache_bsize = 64, 1529 .icache_bsize = 64,
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index fe21674d4f06..ab2d62f70b14 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -176,14 +176,14 @@ transfer_to_handler:
176 cmplw r1,r9 /* if r1 <= ksp_limit */ 176 cmplw r1,r9 /* if r1 <= ksp_limit */
177 ble- stack_ovf /* then the kernel stack overflowed */ 177 ble- stack_ovf /* then the kernel stack overflowed */
1785: 1785:
179#ifdef CONFIG_6xx 179#if defined(CONFIG_6xx) || defined(CONFIG_E500)
180 rlwinm r9,r1,0,0,31-THREAD_SHIFT 180 rlwinm r9,r1,0,0,31-THREAD_SHIFT
181 tophys(r9,r9) /* check local flags */ 181 tophys(r9,r9) /* check local flags */
182 lwz r12,TI_LOCAL_FLAGS(r9) 182 lwz r12,TI_LOCAL_FLAGS(r9)
183 mtcrf 0x01,r12 183 mtcrf 0x01,r12
184 bt- 31-TLF_NAPPING,4f 184 bt- 31-TLF_NAPPING,4f
185 bt- 31-TLF_SLEEPING,7f 185 bt- 31-TLF_SLEEPING,7f
186#endif /* CONFIG_6xx */ 186#endif /* CONFIG_6xx || CONFIG_E500 */
187 .globl transfer_to_handler_cont 187 .globl transfer_to_handler_cont
188transfer_to_handler_cont: 188transfer_to_handler_cont:
1893: 1893:
@@ -196,10 +196,10 @@ transfer_to_handler_cont:
196 SYNC 196 SYNC
197 RFI /* jump to handler, enable MMU */ 197 RFI /* jump to handler, enable MMU */
198 198
199#ifdef CONFIG_6xx 199#if defined (CONFIG_6xx) || defined(CONFIG_E500)
2004: rlwinm r12,r12,0,~_TLF_NAPPING 2004: rlwinm r12,r12,0,~_TLF_NAPPING
201 stw r12,TI_LOCAL_FLAGS(r9) 201 stw r12,TI_LOCAL_FLAGS(r9)
202 b power_save_6xx_restore 202 b power_save_ppc32_restore
203 203
2047: rlwinm r12,r12,0,~_TLF_SLEEPING 2047: rlwinm r12,r12,0,~_TLF_SLEEPING
205 stw r12,TI_LOCAL_FLAGS(r9) 205 stw r12,TI_LOCAL_FLAGS(r9)
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 7c2b65380658..c4268500e856 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -39,6 +39,7 @@
39#include <asm/thread_info.h> 39#include <asm/thread_info.h>
40#include <asm/ppc_asm.h> 40#include <asm/ppc_asm.h>
41#include <asm/asm-offsets.h> 41#include <asm/asm-offsets.h>
42#include <asm/cache.h>
42#include "head_booke.h" 43#include "head_booke.h"
43 44
44/* As with the other PowerPC ports, it is expected that when code 45/* As with the other PowerPC ports, it is expected that when code
@@ -1071,6 +1072,52 @@ _GLOBAL(set_context)
1071 isync /* Force context change */ 1072 isync /* Force context change */
1072 blr 1073 blr
1073 1074
1075_GLOBAL(flush_dcache_L1)
1076 mfspr r3,SPRN_L1CFG0
1077
1078 rlwinm r5,r3,9,3 /* Extract cache block size */
1079 twlgti r5,1 /* Only 32 and 64 byte cache blocks
1080 * are currently defined.
1081 */
1082 li r4,32
1083 subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
1084 * log2(number of ways)
1085 */
1086 slw r5,r4,r5 /* r5 = cache block size */
1087
1088 rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
1089 mulli r7,r7,13 /* An 8-way cache will require 13
1090 * loads per set.
1091 */
1092 slw r7,r7,r6
1093
1094 /* save off HID0 and set DCFA */
1095 mfspr r8,SPRN_HID0
1096 ori r9,r8,HID0_DCFA@l
1097 mtspr SPRN_HID0,r9
1098 isync
1099
1100 lis r4,KERNELBASE@h
1101 mtctr r7
1102
11031: lwz r3,0(r4) /* Load... */
1104 add r4,r4,r5
1105 bdnz 1b
1106
1107 msync
1108 lis r4,KERNELBASE@h
1109 mtctr r7
1110
11111: dcbf 0,r4 /* ...and flush. */
1112 add r4,r4,r5
1113 bdnz 1b
1114
1115 /* restore HID0 */
1116 mtspr SPRN_HID0,r8
1117 isync
1118
1119 blr
1120
1074/* 1121/*
1075 * We put a few things here that have to be page-aligned. This stuff 1122 * We put a few things here that have to be page-aligned. This stuff
1076 * goes at the beginning of the data segment, which is page-aligned. 1123 * goes at the beginning of the data segment, which is page-aligned.
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S
index 01bcd52bbf8e..019b02d8844f 100644
--- a/arch/powerpc/kernel/idle_6xx.S
+++ b/arch/powerpc/kernel/idle_6xx.S
@@ -153,7 +153,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
153 * address of current. R11 points to the exception frame (physical 153 * address of current. R11 points to the exception frame (physical
154 * address). We have to preserve r10. 154 * address). We have to preserve r10.
155 */ 155 */
156_GLOBAL(power_save_6xx_restore) 156_GLOBAL(power_save_ppc32_restore)
157 lwz r9,_LINK(r11) /* interrupted in ppc6xx_idle: */ 157 lwz r9,_LINK(r11) /* interrupted in ppc6xx_idle: */
158 stw r9,_NIP(r11) /* make it do a blr */ 158 stw r9,_NIP(r11) /* make it do a blr */
159 159
diff --git a/arch/powerpc/kernel/idle_e500.S b/arch/powerpc/kernel/idle_e500.S
new file mode 100644
index 000000000000..267adec2491b
--- /dev/null
+++ b/arch/powerpc/kernel/idle_e500.S
@@ -0,0 +1,84 @@
1/*
2 * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
3 * Dave Liu <daveliu@freescale.com>
4 * copy from idle_6xx.S and modify for e500 based processor,
5 * implement the power_save function in idle.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/threads.h>
14#include <asm/reg.h>
15#include <asm/page.h>
16#include <asm/cputable.h>
17#include <asm/thread_info.h>
18#include <asm/ppc_asm.h>
19#include <asm/asm-offsets.h>
20
21 .text
22
23_GLOBAL(e500_idle)
24 rlwinm r3,r1,0,0,31-THREAD_SHIFT /* current thread_info */
25 lwz r4,TI_LOCAL_FLAGS(r3) /* set napping bit */
26 ori r4,r4,_TLF_NAPPING /* so when we take an exception */
27 stw r4,TI_LOCAL_FLAGS(r3) /* it will return to our caller */
28
29 /* Check if we can nap or doze, put HID0 mask in r3 */
30 lis r3,0
31BEGIN_FTR_SECTION
32 lis r3,HID0_DOZE@h
33END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
34
35BEGIN_FTR_SECTION
36 /* Now check if user enabled NAP mode */
37 lis r4,powersave_nap@ha
38 lwz r4,powersave_nap@l(r4)
39 cmpwi 0,r4,0
40 beq 1f
41 stwu r1,-16(r1)
42 mflr r0
43 stw r0,20(r1)
44 bl flush_dcache_L1
45 lwz r0,20(r1)
46 addi r1,r1,16
47 mtlr r0
48 lis r3,HID0_NAP@h
49END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
501:
51 /* Go to NAP or DOZE now */
52 mfspr r4,SPRN_HID0
53 rlwinm r4,r4,0,~(HID0_DOZE|HID0_NAP|HID0_SLEEP)
54 or r4,r4,r3
55 isync
56 mtspr SPRN_HID0,r4
57 isync
58
59 mfmsr r7
60 oris r7,r7,MSR_WE@h
61 ori r7,r7,MSR_EE
62 msync
63 mtmsr r7
64 isync
652: b 2b
66
67/*
68 * Return from NAP/DOZE mode, restore some CPU specific registers,
69 * r2 containing physical address of current.
70 * r11 points to the exception frame (physical address).
71 * We have to preserve r10.
72 */
73_GLOBAL(power_save_ppc32_restore)
74 lwz r9,_LINK(r11) /* interrupted in e500_idle */
75 stw r9,_NIP(r11) /* make it do a blr */
76
77#ifdef CONFIG_SMP
78 mfspr r12,SPRN_SPRG3
79 lwz r11,TI_CPU(r12) /* get cpu number * 4 */
80 slwi r11,r11,2
81#else
82 li r11,0
83#endif
84 b transfer_to_handler_cont
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index bef0be3fd98b..9e83add54290 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -127,6 +127,11 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys)
127 ppc_md.power_save = ppc6xx_idle; 127 ppc_md.power_save = ppc6xx_idle;
128#endif 128#endif
129 129
130#ifdef CONFIG_E500
131 if (cpu_has_feature(CPU_FTR_CAN_DOZE) ||
132 cpu_has_feature(CPU_FTR_CAN_NAP))
133 ppc_md.power_save = e500_idle;
134#endif
130 if (ppc_md.progress) 135 if (ppc_md.progress)
131 ppc_md.progress("id mach(): done", 0x200); 136 ppc_md.progress("id mach(): done", 0x200);
132} 137}
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index a3dce178b728..18feb63dd3c0 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -347,12 +347,13 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
347#define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ 347#define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \
348 CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \ 348 CPU_FTR_NODSISRALIGN | CPU_FTR_COHERENT_ICACHE | \
349 CPU_FTR_UNIFIED_ID_CACHE) 349 CPU_FTR_UNIFIED_ID_CACHE)
350#define CPU_FTRS_E500 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ 350#define CPU_FTRS_E500 (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
351 CPU_FTR_NODSISRALIGN) 351 CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN)
352#define CPU_FTRS_E500_2 (CPU_FTR_USE_TB | CPU_FTR_SPE_COMP | \ 352#define CPU_FTRS_E500_2 (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
353 CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN) 353 CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | \
354#define CPU_FTRS_E500MC (CPU_FTR_USE_TB | CPU_FTR_BIG_PHYS | \
355 CPU_FTR_NODSISRALIGN) 354 CPU_FTR_NODSISRALIGN)
355#define CPU_FTRS_E500MC (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
356 CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN)
356#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) 357#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
357 358
358/* 64-bit CPUs */ 359/* 64-bit CPUs */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 54ed64df95b8..989922621e35 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -262,6 +262,7 @@ struct machdep_calls {
262#endif 262#endif
263}; 263};
264 264
265extern void e500_idle(void);
265extern void power4_idle(void); 266extern void power4_idle(void);
266extern void power4_cpu_offline_powersave(void); 267extern void power4_cpu_offline_powersave(void);
267extern void ppc6xx_idle(void); 268extern void ppc6xx_idle(void);
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index edc0cfd7f6e2..079999b032af 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -240,7 +240,7 @@
240#define HID0_DAPUEN (1<<8) /* Debug APU enable */ 240#define HID0_DAPUEN (1<<8) /* Debug APU enable */
241#define HID0_SGE (1<<7) /* Store Gathering Enable */ 241#define HID0_SGE (1<<7) /* Store Gathering Enable */
242#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */ 242#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */
243#define HID0_DFCA (1<<6) /* Data Cache Flush Assist */ 243#define HID0_DCFA (1<<6) /* Data Cache Flush Assist */
244#define HID0_LRSTK (1<<4) /* Link register stack - 745x */ 244#define HID0_LRSTK (1<<4) /* Link register stack - 745x */
245#define HID0_BTIC (1<<5) /* Branch Target Instr Cache Enable */ 245#define HID0_BTIC (1<<5) /* Branch Target Instr Cache Enable */
246#define HID0_ABE (1<<3) /* Address Broadcast Enable */ 246#define HID0_ABE (1<<3) /* Address Broadcast Enable */
diff --git a/include/asm-powerpc/reg_booke.h b/include/asm-powerpc/reg_booke.h
index a1ab2ba8f1b2..a5e8903bbc87 100644
--- a/include/asm-powerpc/reg_booke.h
+++ b/include/asm-powerpc/reg_booke.h
@@ -61,6 +61,8 @@
61#define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */ 61#define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */
62#define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */ 62#define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */
63#define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */ 63#define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */
64#define SPRN_L1CFG0 0x203 /* L1 Cache Configure Register 0 */
65#define SPRN_L1CFG1 0x204 /* L1 Cache Configure Register 1 */
64#define SPRN_ATB 0x20E /* Alternate Time Base */ 66#define SPRN_ATB 0x20E /* Alternate Time Base */
65#define SPRN_ATBL 0x20E /* Alternate Time Base Lower */ 67#define SPRN_ATBL 0x20E /* Alternate Time Base Lower */
66#define SPRN_ATBU 0x20F /* Alternate Time Base Upper */ 68#define SPRN_ATBU 0x20F /* Alternate Time Base Upper */