aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-11-24 02:32:11 -0500
committerPaul Mundt <lethal@linux-sh.org>2009-11-24 02:32:11 -0500
commit49fb2cd2571e0134e5a12c5abab227696e4940c7 (patch)
tree9a77364e988ef3f3af24feee3f5bb91bd0c34129 /arch/sh/kernel/cpu
parentdfc349402de8e95f6a42e8341e9ea193b718eee3 (diff)
parent260af56271f79da0e37faa5a99b1786b221297e5 (diff)
Merge branch 'master' into sh/st-integration
Diffstat (limited to 'arch/sh/kernel/cpu')
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/init.c11
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S33
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile8
-rw-r--r--arch/sh/kernel/cpu/sh4/perf_event.c253
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7724.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/perf_event.c269
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7724.c249
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c45
-rw-r--r--arch/sh/kernel/cpu/sh4a/smp-shx3.c37
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S2
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c42
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm.c117
-rw-r--r--arch/sh/kernel/cpu/shmobile/sleep.S344
-rw-r--r--arch/sh/kernel/cpu/ubc.S59
16 files changed, 1140 insertions, 333 deletions
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 3d6b9312dc47..d97c803719ec 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
15 15
16# Common interfaces. 16# Common interfaces.
17 17
18obj-$(CONFIG_UBC_WAKEUP) += ubc.o
19obj-$(CONFIG_SH_ADC) += adc.o 18obj-$(CONFIG_SH_ADC) += adc.o
20obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o 19obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
21 20
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index e932ebef4738..580d58b94cc5 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -338,17 +338,6 @@ asmlinkage void __init sh_cpu_init(void)
338 } 338 }
339#endif 339#endif
340 340
341 /*
342 * Some brain-damaged loaders decided it would be a good idea to put
343 * the UBC to sleep. This causes some issues when it comes to things
344 * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
345 * we wake it up and hope that all is well.
346 */
347#ifdef CONFIG_SUPERH32
348 if (raw_smp_processor_id() == 0)
349 ubc_wakeup();
350#endif
351
352 speculative_execution_init(); 341 speculative_execution_init();
353 expmask_init(); 342 expmask_init();
354} 343}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index bb407ef0b91e..3f7e2a22c7c2 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -297,41 +297,8 @@ ENTRY(vbr_base)
297! 297!
298 .balign 256,0,256 298 .balign 256,0,256
299general_exception: 299general_exception:
300#ifndef CONFIG_CPU_SUBTYPE_SHX3
301 bra handle_exception 300 bra handle_exception
302 sts pr, k3 ! save original pr value in k3 301 sts pr, k3 ! save original pr value in k3
303#else
304 mov.l 1f, k4
305 mov.l @k4, k4
306
307 ! Is EXPEVT larger than 0x800?
308 mov #0x8, k0
309 shll8 k0
310 cmp/hs k0, k4
311 bf 0f
312
313 ! then add 0x580 (k2 is 0xd80 or 0xda0)
314 mov #0x58, k0
315 shll2 k0
316 shll2 k0
317 add k0, k4
3180:
319 ! Setup stack and save DSP context (k0 contains original r15 on return)
320 bsr prepare_stack
321 nop
322
323 ! Save registers / Switch to bank 0
324 mov k4, k2 ! keep vector in k2
325 mov.l 1f, k4 ! SR bits to clear in k4
326 bsr save_regs ! needs original pr value in k3
327 nop
328
329 bra handle_exception_special
330 nop
331
332 .align 2
3331: .long EXPEVT
334#endif
335 302
336! prepare_stack() 303! prepare_stack()
337! - roll back gRB 304! - roll back gRB
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 203b18347b83..3a1dbc709831 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -9,6 +9,11 @@ obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o)
9obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o 9obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o
10obj-$(CONFIG_SH_STORE_QUEUES) += sq.o 10obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
11 11
12# Perf events
13perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o
14perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o
15perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o
16
12# CPU subtype setup 17# CPU subtype setup
13obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o 18obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
14obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o 19obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o
@@ -27,4 +32,5 @@ endif
27# Additional clocks by subtype 32# Additional clocks by subtype
28clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o 33clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o
29 34
30obj-y += $(clock-y) 35obj-y += $(clock-y)
36obj-$(CONFIG_PERF_EVENTS) += $(perf-y)
diff --git a/arch/sh/kernel/cpu/sh4/perf_event.c b/arch/sh/kernel/cpu/sh4/perf_event.c
new file mode 100644
index 000000000000..7f9ecc9c2d02
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/perf_event.c
@@ -0,0 +1,253 @@
1/*
2 * Performance events support for SH7750-style performance counters
3 *
4 * Copyright (C) 2009 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/io.h>
13#include <linux/irq.h>
14#include <linux/perf_event.h>
15#include <asm/processor.h>
16
17#define PM_CR_BASE 0xff000084 /* 16-bit */
18#define PM_CTR_BASE 0xff100004 /* 32-bit */
19
20#define PMCR(n) (PM_CR_BASE + ((n) * 0x04))
21#define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08))
22#define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08))
23
24#define PMCR_PMM_MASK 0x0000003f
25
26#define PMCR_CLKF 0x00000100
27#define PMCR_PMCLR 0x00002000
28#define PMCR_PMST 0x00004000
29#define PMCR_PMEN 0x00008000
30
31static struct sh_pmu sh7750_pmu;
32
33/*
34 * There are a number of events supported by each counter (33 in total).
35 * Since we have 2 counters, each counter will take the event code as it
36 * corresponds to the PMCR PMM setting. Each counter can be configured
37 * independently.
38 *
39 * Event Code Description
40 * ---------- -----------
41 *
42 * 0x01 Operand read access
43 * 0x02 Operand write access
44 * 0x03 UTLB miss
45 * 0x04 Operand cache read miss
46 * 0x05 Operand cache write miss
47 * 0x06 Instruction fetch (w/ cache)
48 * 0x07 Instruction TLB miss
49 * 0x08 Instruction cache miss
50 * 0x09 All operand accesses
51 * 0x0a All instruction accesses
52 * 0x0b OC RAM operand access
53 * 0x0d On-chip I/O space access
54 * 0x0e Operand access (r/w)
55 * 0x0f Operand cache miss (r/w)
56 * 0x10 Branch instruction
57 * 0x11 Branch taken
58 * 0x12 BSR/BSRF/JSR
59 * 0x13 Instruction execution
60 * 0x14 Instruction execution in parallel
61 * 0x15 FPU Instruction execution
62 * 0x16 Interrupt
63 * 0x17 NMI
64 * 0x18 trapa instruction execution
65 * 0x19 UBCA match
66 * 0x1a UBCB match
67 * 0x21 Instruction cache fill
68 * 0x22 Operand cache fill
69 * 0x23 Elapsed time
70 * 0x24 Pipeline freeze by I-cache miss
71 * 0x25 Pipeline freeze by D-cache miss
72 * 0x27 Pipeline freeze by branch instruction
73 * 0x28 Pipeline freeze by CPU register
74 * 0x29 Pipeline freeze by FPU
75 */
76
77static const int sh7750_general_events[] = {
78 [PERF_COUNT_HW_CPU_CYCLES] = 0x0023,
79 [PERF_COUNT_HW_INSTRUCTIONS] = 0x000a,
80 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0006, /* I-cache */
81 [PERF_COUNT_HW_CACHE_MISSES] = 0x0008, /* I-cache */
82 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0010,
83 [PERF_COUNT_HW_BRANCH_MISSES] = -1,
84 [PERF_COUNT_HW_BUS_CYCLES] = -1,
85};
86
87#define C(x) PERF_COUNT_HW_CACHE_##x
88
89static const int sh7750_cache_events
90 [PERF_COUNT_HW_CACHE_MAX]
91 [PERF_COUNT_HW_CACHE_OP_MAX]
92 [PERF_COUNT_HW_CACHE_RESULT_MAX] =
93{
94 [ C(L1D) ] = {
95 [ C(OP_READ) ] = {
96 [ C(RESULT_ACCESS) ] = 0x0001,
97 [ C(RESULT_MISS) ] = 0x0004,
98 },
99 [ C(OP_WRITE) ] = {
100 [ C(RESULT_ACCESS) ] = 0x0002,
101 [ C(RESULT_MISS) ] = 0x0005,
102 },
103 [ C(OP_PREFETCH) ] = {
104 [ C(RESULT_ACCESS) ] = 0,
105 [ C(RESULT_MISS) ] = 0,
106 },
107 },
108
109 [ C(L1I) ] = {
110 [ C(OP_READ) ] = {
111 [ C(RESULT_ACCESS) ] = 0x0006,
112 [ C(RESULT_MISS) ] = 0x0008,
113 },
114 [ C(OP_WRITE) ] = {
115 [ C(RESULT_ACCESS) ] = -1,
116 [ C(RESULT_MISS) ] = -1,
117 },
118 [ C(OP_PREFETCH) ] = {
119 [ C(RESULT_ACCESS) ] = 0,
120 [ C(RESULT_MISS) ] = 0,
121 },
122 },
123
124 [ C(LL) ] = {
125 [ C(OP_READ) ] = {
126 [ C(RESULT_ACCESS) ] = 0,
127 [ C(RESULT_MISS) ] = 0,
128 },
129 [ C(OP_WRITE) ] = {
130 [ C(RESULT_ACCESS) ] = 0,
131 [ C(RESULT_MISS) ] = 0,
132 },
133 [ C(OP_PREFETCH) ] = {
134 [ C(RESULT_ACCESS) ] = 0,
135 [ C(RESULT_MISS) ] = 0,
136 },
137 },
138
139 [ C(DTLB) ] = {
140 [ C(OP_READ) ] = {
141 [ C(RESULT_ACCESS) ] = 0,
142 [ C(RESULT_MISS) ] = 0x0003,
143 },
144 [ C(OP_WRITE) ] = {
145 [ C(RESULT_ACCESS) ] = 0,
146 [ C(RESULT_MISS) ] = 0,
147 },
148 [ C(OP_PREFETCH) ] = {
149 [ C(RESULT_ACCESS) ] = 0,
150 [ C(RESULT_MISS) ] = 0,
151 },
152 },
153
154 [ C(ITLB) ] = {
155 [ C(OP_READ) ] = {
156 [ C(RESULT_ACCESS) ] = 0,
157 [ C(RESULT_MISS) ] = 0x0007,
158 },
159 [ C(OP_WRITE) ] = {
160 [ C(RESULT_ACCESS) ] = -1,
161 [ C(RESULT_MISS) ] = -1,
162 },
163 [ C(OP_PREFETCH) ] = {
164 [ C(RESULT_ACCESS) ] = -1,
165 [ C(RESULT_MISS) ] = -1,
166 },
167 },
168
169 [ C(BPU) ] = {
170 [ C(OP_READ) ] = {
171 [ C(RESULT_ACCESS) ] = -1,
172 [ C(RESULT_MISS) ] = -1,
173 },
174 [ C(OP_WRITE) ] = {
175 [ C(RESULT_ACCESS) ] = -1,
176 [ C(RESULT_MISS) ] = -1,
177 },
178 [ C(OP_PREFETCH) ] = {
179 [ C(RESULT_ACCESS) ] = -1,
180 [ C(RESULT_MISS) ] = -1,
181 },
182 },
183};
184
185static int sh7750_event_map(int event)
186{
187 return sh7750_general_events[event];
188}
189
190static u64 sh7750_pmu_read(int idx)
191{
192 return (u64)((u64)(__raw_readl(PMCTRH(idx)) & 0xffff) << 32) |
193 __raw_readl(PMCTRL(idx));
194}
195
196static void sh7750_pmu_disable(struct hw_perf_event *hwc, int idx)
197{
198 unsigned int tmp;
199
200 tmp = __raw_readw(PMCR(idx));
201 tmp &= ~(PMCR_PMM_MASK | PMCR_PMEN);
202 __raw_writew(tmp, PMCR(idx));
203}
204
205static void sh7750_pmu_enable(struct hw_perf_event *hwc, int idx)
206{
207 __raw_writew(__raw_readw(PMCR(idx)) | PMCR_PMCLR, PMCR(idx));
208 __raw_writew(hwc->config | PMCR_PMEN | PMCR_PMST, PMCR(idx));
209}
210
211static void sh7750_pmu_disable_all(void)
212{
213 int i;
214
215 for (i = 0; i < sh7750_pmu.num_events; i++)
216 __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
217}
218
219static void sh7750_pmu_enable_all(void)
220{
221 int i;
222
223 for (i = 0; i < sh7750_pmu.num_events; i++)
224 __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMEN, PMCR(i));
225}
226
227static struct sh_pmu sh7750_pmu = {
228 .name = "SH7750",
229 .num_events = 2,
230 .event_map = sh7750_event_map,
231 .max_events = ARRAY_SIZE(sh7750_general_events),
232 .raw_event_mask = PMCR_PMM_MASK,
233 .cache_events = &sh7750_cache_events,
234 .read = sh7750_pmu_read,
235 .disable = sh7750_pmu_disable,
236 .enable = sh7750_pmu_enable,
237 .disable_all = sh7750_pmu_disable_all,
238 .enable_all = sh7750_pmu_enable_all,
239};
240
241static int __init sh7750_pmu_init(void)
242{
243 /*
244 * Make sure this CPU actually has perf counters.
245 */
246 if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
247 pr_notice("HW perf events unsupported, software events only.\n");
248 return -ENODEV;
249 }
250
251 return register_sh_pmu(&sh7750_pmu);
252}
253arch_initcall(sh7750_pmu_init);
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index 490d5dc9e372..33bab477d2e2 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -44,3 +44,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
44obj-y += $(clock-y) 44obj-y += $(clock-y)
45obj-$(CONFIG_SMP) += $(smp-y) 45obj-$(CONFIG_SMP) += $(smp-y)
46obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) 46obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y)
47obj-$(CONFIG_PERF_EVENTS) += perf_event.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index dfe9192be63e..9db743802f06 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -152,7 +152,7 @@ struct clk div6_clks[] = {
152 SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0), 152 SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0),
153 SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0), 153 SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0),
154 SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0), 154 SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0),
155 SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0), 155 SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
156}; 156};
157 157
158#define R_CLK (&r_clk) 158#define R_CLK (&r_clk)
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c
new file mode 100644
index 000000000000..eddc21973fa1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/perf_event.c
@@ -0,0 +1,269 @@
1/*
2 * Performance events support for SH-4A performance counters
3 *
4 * Copyright (C) 2009 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/io.h>
13#include <linux/irq.h>
14#include <linux/perf_event.h>
15#include <asm/processor.h>
16
17#define PPC_CCBR(idx) (0xff200800 + (sizeof(u32) * idx))
18#define PPC_PMCTR(idx) (0xfc100000 + (sizeof(u32) * idx))
19
20#define CCBR_CIT_MASK (0x7ff << 6)
21#define CCBR_DUC (1 << 3)
22#define CCBR_CMDS (1 << 1)
23#define CCBR_PPCE (1 << 0)
24
25#define PPC_PMCAT 0xfc100080
26
27#define PMCAT_OVF3 (1 << 27)
28#define PMCAT_CNN3 (1 << 26)
29#define PMCAT_CLR3 (1 << 25)
30#define PMCAT_OVF2 (1 << 19)
31#define PMCAT_CLR2 (1 << 17)
32#define PMCAT_OVF1 (1 << 11)
33#define PMCAT_CNN1 (1 << 10)
34#define PMCAT_CLR1 (1 << 9)
35#define PMCAT_OVF0 (1 << 3)
36#define PMCAT_CLR0 (1 << 1)
37
38static struct sh_pmu sh4a_pmu;
39
40/*
41 * Supported raw event codes:
42 *
43 * Event Code Description
44 * ---------- -----------
45 *
46 * 0x0000 number of elapsed cycles
47 * 0x0200 number of elapsed cycles in privileged mode
48 * 0x0280 number of elapsed cycles while SR.BL is asserted
49 * 0x0202 instruction execution
50 * 0x0203 instruction execution in parallel
51 * 0x0204 number of unconditional branches
52 * 0x0208 number of exceptions
53 * 0x0209 number of interrupts
54 * 0x0220 UTLB miss caused by instruction fetch
55 * 0x0222 UTLB miss caused by operand access
56 * 0x02a0 number of ITLB misses
57 * 0x0028 number of accesses to instruction memories
58 * 0x0029 number of accesses to instruction cache
59 * 0x002a instruction cache miss
60 * 0x022e number of access to instruction X/Y memory
61 * 0x0030 number of reads to operand memories
62 * 0x0038 number of writes to operand memories
63 * 0x0031 number of operand cache read accesses
64 * 0x0039 number of operand cache write accesses
65 * 0x0032 operand cache read miss
66 * 0x003a operand cache write miss
67 * 0x0236 number of reads to operand X/Y memory
68 * 0x023e number of writes to operand X/Y memory
69 * 0x0237 number of reads to operand U memory
70 * 0x023f number of writes to operand U memory
71 * 0x0337 number of U memory read buffer misses
72 * 0x02b4 number of wait cycles due to operand read access
73 * 0x02bc number of wait cycles due to operand write access
74 * 0x0033 number of wait cycles due to operand cache read miss
75 * 0x003b number of wait cycles due to operand cache write miss
76 */
77
78/*
79 * Special reserved bits used by hardware emulators, read values will
80 * vary, but writes must always be 0.
81 */
82#define PMCAT_EMU_CLR_MASK ((1 << 24) | (1 << 16) | (1 << 8) | (1 << 0))
83
84static const int sh4a_general_events[] = {
85 [PERF_COUNT_HW_CPU_CYCLES] = 0x0000,
86 [PERF_COUNT_HW_INSTRUCTIONS] = 0x0202,
87 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0029, /* I-cache */
88 [PERF_COUNT_HW_CACHE_MISSES] = 0x002a, /* I-cache */
89 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0204,
90 [PERF_COUNT_HW_BRANCH_MISSES] = -1,
91 [PERF_COUNT_HW_BUS_CYCLES] = -1,
92};
93
94#define C(x) PERF_COUNT_HW_CACHE_##x
95
96static const int sh4a_cache_events
97 [PERF_COUNT_HW_CACHE_MAX]
98 [PERF_COUNT_HW_CACHE_OP_MAX]
99 [PERF_COUNT_HW_CACHE_RESULT_MAX] =
100{
101 [ C(L1D) ] = {
102 [ C(OP_READ) ] = {
103 [ C(RESULT_ACCESS) ] = 0x0031,
104 [ C(RESULT_MISS) ] = 0x0032,
105 },
106 [ C(OP_WRITE) ] = {
107 [ C(RESULT_ACCESS) ] = 0x0039,
108 [ C(RESULT_MISS) ] = 0x003a,
109 },
110 [ C(OP_PREFETCH) ] = {
111 [ C(RESULT_ACCESS) ] = 0,
112 [ C(RESULT_MISS) ] = 0,
113 },
114 },
115
116 [ C(L1I) ] = {
117 [ C(OP_READ) ] = {
118 [ C(RESULT_ACCESS) ] = 0x0029,
119 [ C(RESULT_MISS) ] = 0x002a,
120 },
121 [ C(OP_WRITE) ] = {
122 [ C(RESULT_ACCESS) ] = -1,
123 [ C(RESULT_MISS) ] = -1,
124 },
125 [ C(OP_PREFETCH) ] = {
126 [ C(RESULT_ACCESS) ] = 0,
127 [ C(RESULT_MISS) ] = 0,
128 },
129 },
130
131 [ C(LL) ] = {
132 [ C(OP_READ) ] = {
133 [ C(RESULT_ACCESS) ] = 0x0030,
134 [ C(RESULT_MISS) ] = 0,
135 },
136 [ C(OP_WRITE) ] = {
137 [ C(RESULT_ACCESS) ] = 0x0038,
138 [ C(RESULT_MISS) ] = 0,
139 },
140 [ C(OP_PREFETCH) ] = {
141 [ C(RESULT_ACCESS) ] = 0,
142 [ C(RESULT_MISS) ] = 0,
143 },
144 },
145
146 [ C(DTLB) ] = {
147 [ C(OP_READ) ] = {
148 [ C(RESULT_ACCESS) ] = 0x0222,
149 [ C(RESULT_MISS) ] = 0x0220,
150 },
151 [ C(OP_WRITE) ] = {
152 [ C(RESULT_ACCESS) ] = 0,
153 [ C(RESULT_MISS) ] = 0,
154 },
155 [ C(OP_PREFETCH) ] = {
156 [ C(RESULT_ACCESS) ] = 0,
157 [ C(RESULT_MISS) ] = 0,
158 },
159 },
160
161 [ C(ITLB) ] = {
162 [ C(OP_READ) ] = {
163 [ C(RESULT_ACCESS) ] = 0,
164 [ C(RESULT_MISS) ] = 0x02a0,
165 },
166 [ C(OP_WRITE) ] = {
167 [ C(RESULT_ACCESS) ] = -1,
168 [ C(RESULT_MISS) ] = -1,
169 },
170 [ C(OP_PREFETCH) ] = {
171 [ C(RESULT_ACCESS) ] = -1,
172 [ C(RESULT_MISS) ] = -1,
173 },
174 },
175
176 [ C(BPU) ] = {
177 [ C(OP_READ) ] = {
178 [ C(RESULT_ACCESS) ] = -1,
179 [ C(RESULT_MISS) ] = -1,
180 },
181 [ C(OP_WRITE) ] = {
182 [ C(RESULT_ACCESS) ] = -1,
183 [ C(RESULT_MISS) ] = -1,
184 },
185 [ C(OP_PREFETCH) ] = {
186 [ C(RESULT_ACCESS) ] = -1,
187 [ C(RESULT_MISS) ] = -1,
188 },
189 },
190};
191
192static int sh4a_event_map(int event)
193{
194 return sh4a_general_events[event];
195}
196
197static u64 sh4a_pmu_read(int idx)
198{
199 return __raw_readl(PPC_PMCTR(idx));
200}
201
202static void sh4a_pmu_disable(struct hw_perf_event *hwc, int idx)
203{
204 unsigned int tmp;
205
206 tmp = __raw_readl(PPC_CCBR(idx));
207 tmp &= ~(CCBR_CIT_MASK | CCBR_DUC);
208 __raw_writel(tmp, PPC_CCBR(idx));
209}
210
211static void sh4a_pmu_enable(struct hw_perf_event *hwc, int idx)
212{
213 unsigned int tmp;
214
215 tmp = __raw_readl(PPC_PMCAT);
216 tmp &= ~PMCAT_EMU_CLR_MASK;
217 tmp |= idx ? PMCAT_CLR1 : PMCAT_CLR0;
218 __raw_writel(tmp, PPC_PMCAT);
219
220 tmp = __raw_readl(PPC_CCBR(idx));
221 tmp |= (hwc->config << 6) | CCBR_CMDS | CCBR_PPCE;
222 __raw_writel(tmp, PPC_CCBR(idx));
223
224 __raw_writel(__raw_readl(PPC_CCBR(idx)) | CCBR_DUC, PPC_CCBR(idx));
225}
226
227static void sh4a_pmu_disable_all(void)
228{
229 int i;
230
231 for (i = 0; i < sh4a_pmu.num_events; i++)
232 __raw_writel(__raw_readl(PPC_CCBR(i)) & ~CCBR_DUC, PPC_CCBR(i));
233}
234
235static void sh4a_pmu_enable_all(void)
236{
237 int i;
238
239 for (i = 0; i < sh4a_pmu.num_events; i++)
240 __raw_writel(__raw_readl(PPC_CCBR(i)) | CCBR_DUC, PPC_CCBR(i));
241}
242
243static struct sh_pmu sh4a_pmu = {
244 .name = "SH-4A",
245 .num_events = 2,
246 .event_map = sh4a_event_map,
247 .max_events = ARRAY_SIZE(sh4a_general_events),
248 .raw_event_mask = 0x3ff,
249 .cache_events = &sh4a_cache_events,
250 .read = sh4a_pmu_read,
251 .disable = sh4a_pmu_disable,
252 .enable = sh4a_pmu_enable,
253 .disable_all = sh4a_pmu_disable_all,
254 .enable_all = sh4a_pmu_enable_all,
255};
256
257static int __init sh4a_pmu_init(void)
258{
259 /*
260 * Make sure this CPU actually has perf counters.
261 */
262 if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
263 pr_notice("HW perf events unsupported, software events only.\n");
264 return -ENODEV;
265 }
266
267 return register_sh_pmu(&sh4a_pmu);
268}
269arch_initcall(sh4a_pmu_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index f3851fd757ec..9c3cc8f638b6 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -20,6 +20,8 @@
20#include <linux/uio_driver.h> 20#include <linux/uio_driver.h>
21#include <linux/sh_timer.h> 21#include <linux/sh_timer.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/notifier.h>
24#include <asm/suspend.h>
23#include <asm/clock.h> 25#include <asm/clock.h>
24#include <asm/mmzone.h> 26#include <asm/mmzone.h>
25#include <cpu/sh7724.h> 27#include <cpu/sh7724.h>
@@ -523,6 +525,70 @@ static struct platform_device jpu_device = {
523 }, 525 },
524}; 526};
525 527
528/* SPU2DSP0 */
529static struct uio_info spu0_platform_data = {
530 .name = "SPU2DSP0",
531 .version = "0",
532 .irq = 86,
533};
534
535static struct resource spu0_resources[] = {
536 [0] = {
537 .name = "SPU2DSP0",
538 .start = 0xFE200000,
539 .end = 0xFE2FFFFF,
540 .flags = IORESOURCE_MEM,
541 },
542 [1] = {
543 /* place holder for contiguous memory */
544 },
545};
546
547static struct platform_device spu0_device = {
548 .name = "uio_pdrv_genirq",
549 .id = 4,
550 .dev = {
551 .platform_data = &spu0_platform_data,
552 },
553 .resource = spu0_resources,
554 .num_resources = ARRAY_SIZE(spu0_resources),
555 .archdata = {
556 .hwblk_id = HWBLK_SPU,
557 },
558};
559
560/* SPU2DSP1 */
561static struct uio_info spu1_platform_data = {
562 .name = "SPU2DSP1",
563 .version = "0",
564 .irq = 87,
565};
566
567static struct resource spu1_resources[] = {
568 [0] = {
569 .name = "SPU2DSP1",
570 .start = 0xFE300000,
571 .end = 0xFE3FFFFF,
572 .flags = IORESOURCE_MEM,
573 },
574 [1] = {
575 /* place holder for contiguous memory */
576 },
577};
578
579static struct platform_device spu1_device = {
580 .name = "uio_pdrv_genirq",
581 .id = 5,
582 .dev = {
583 .platform_data = &spu1_platform_data,
584 },
585 .resource = spu1_resources,
586 .num_resources = ARRAY_SIZE(spu1_resources),
587 .archdata = {
588 .hwblk_id = HWBLK_SPU,
589 },
590};
591
526static struct platform_device *sh7724_devices[] __initdata = { 592static struct platform_device *sh7724_devices[] __initdata = {
527 &cmt_device, 593 &cmt_device,
528 &tmu0_device, 594 &tmu0_device,
@@ -539,6 +605,8 @@ static struct platform_device *sh7724_devices[] __initdata = {
539 &veu0_device, 605 &veu0_device,
540 &veu1_device, 606 &veu1_device,
541 &jpu_device, 607 &jpu_device,
608 &spu0_device,
609 &spu1_device,
542}; 610};
543 611
544static int __init sh7724_devices_setup(void) 612static int __init sh7724_devices_setup(void)
@@ -547,6 +615,8 @@ static int __init sh7724_devices_setup(void)
547 platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); 615 platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
548 platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20); 616 platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
549 platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20); 617 platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
618 platform_resource_setup_memory(&spu0_device, "spu0", 2 << 20);
619 platform_resource_setup_memory(&spu1_device, "spu1", 2 << 20);
550 620
551 return platform_add_devices(sh7724_devices, 621 return platform_add_devices(sh7724_devices,
552 ARRAY_SIZE(sh7724_devices)); 622 ARRAY_SIZE(sh7724_devices));
@@ -827,3 +897,182 @@ void __init plat_irq_setup(void)
827{ 897{
828 register_intc_controller(&intc_desc); 898 register_intc_controller(&intc_desc);
829} 899}
900
901static struct {
902 /* BSC */
903 unsigned long mmselr;
904 unsigned long cs0bcr;
905 unsigned long cs4bcr;
906 unsigned long cs5abcr;
907 unsigned long cs5bbcr;
908 unsigned long cs6abcr;
909 unsigned long cs6bbcr;
910 unsigned long cs4wcr;
911 unsigned long cs5awcr;
912 unsigned long cs5bwcr;
913 unsigned long cs6awcr;
914 unsigned long cs6bwcr;
915 /* INTC */
916 unsigned short ipra;
917 unsigned short iprb;
918 unsigned short iprc;
919 unsigned short iprd;
920 unsigned short ipre;
921 unsigned short iprf;
922 unsigned short iprg;
923 unsigned short iprh;
924 unsigned short ipri;
925 unsigned short iprj;
926 unsigned short iprk;
927 unsigned short iprl;
928 unsigned char imr0;
929 unsigned char imr1;
930 unsigned char imr2;
931 unsigned char imr3;
932 unsigned char imr4;
933 unsigned char imr5;
934 unsigned char imr6;
935 unsigned char imr7;
936 unsigned char imr8;
937 unsigned char imr9;
938 unsigned char imr10;
939 unsigned char imr11;
940 unsigned char imr12;
941 /* RWDT */
942 unsigned short rwtcnt;
943 unsigned short rwtcsr;
944} sh7724_rstandby_state;
945
946static int sh7724_pre_sleep_notifier_call(struct notifier_block *nb,
947 unsigned long flags, void *unused)
948{
949 if (!(flags & SUSP_SH_RSTANDBY))
950 return NOTIFY_DONE;
951
952 /* BCR */
953 sh7724_rstandby_state.mmselr = __raw_readl(0xff800020); /* MMSELR */
954 sh7724_rstandby_state.mmselr |= 0xa5a50000;
955 sh7724_rstandby_state.cs0bcr = __raw_readl(0xfec10004); /* CS0BCR */
956 sh7724_rstandby_state.cs4bcr = __raw_readl(0xfec10010); /* CS4BCR */
957 sh7724_rstandby_state.cs5abcr = __raw_readl(0xfec10014); /* CS5ABCR */
958 sh7724_rstandby_state.cs5bbcr = __raw_readl(0xfec10018); /* CS5BBCR */
959 sh7724_rstandby_state.cs6abcr = __raw_readl(0xfec1001c); /* CS6ABCR */
960 sh7724_rstandby_state.cs6bbcr = __raw_readl(0xfec10020); /* CS6BBCR */
961 sh7724_rstandby_state.cs4wcr = __raw_readl(0xfec10030); /* CS4WCR */
962 sh7724_rstandby_state.cs5awcr = __raw_readl(0xfec10034); /* CS5AWCR */
963 sh7724_rstandby_state.cs5bwcr = __raw_readl(0xfec10038); /* CS5BWCR */
964 sh7724_rstandby_state.cs6awcr = __raw_readl(0xfec1003c); /* CS6AWCR */
965 sh7724_rstandby_state.cs6bwcr = __raw_readl(0xfec10040); /* CS6BWCR */
966
967 /* INTC */
968 sh7724_rstandby_state.ipra = __raw_readw(0xa4080000); /* IPRA */
969 sh7724_rstandby_state.iprb = __raw_readw(0xa4080004); /* IPRB */
970 sh7724_rstandby_state.iprc = __raw_readw(0xa4080008); /* IPRC */
971 sh7724_rstandby_state.iprd = __raw_readw(0xa408000c); /* IPRD */
972 sh7724_rstandby_state.ipre = __raw_readw(0xa4080010); /* IPRE */
973 sh7724_rstandby_state.iprf = __raw_readw(0xa4080014); /* IPRF */
974 sh7724_rstandby_state.iprg = __raw_readw(0xa4080018); /* IPRG */
975 sh7724_rstandby_state.iprh = __raw_readw(0xa408001c); /* IPRH */
976 sh7724_rstandby_state.ipri = __raw_readw(0xa4080020); /* IPRI */
977 sh7724_rstandby_state.iprj = __raw_readw(0xa4080024); /* IPRJ */
978 sh7724_rstandby_state.iprk = __raw_readw(0xa4080028); /* IPRK */
979 sh7724_rstandby_state.iprl = __raw_readw(0xa408002c); /* IPRL */
980 sh7724_rstandby_state.imr0 = __raw_readb(0xa4080080); /* IMR0 */
981 sh7724_rstandby_state.imr1 = __raw_readb(0xa4080084); /* IMR1 */
982 sh7724_rstandby_state.imr2 = __raw_readb(0xa4080088); /* IMR2 */
983 sh7724_rstandby_state.imr3 = __raw_readb(0xa408008c); /* IMR3 */
984 sh7724_rstandby_state.imr4 = __raw_readb(0xa4080090); /* IMR4 */
985 sh7724_rstandby_state.imr5 = __raw_readb(0xa4080094); /* IMR5 */
986 sh7724_rstandby_state.imr6 = __raw_readb(0xa4080098); /* IMR6 */
987 sh7724_rstandby_state.imr7 = __raw_readb(0xa408009c); /* IMR7 */
988 sh7724_rstandby_state.imr8 = __raw_readb(0xa40800a0); /* IMR8 */
989 sh7724_rstandby_state.imr9 = __raw_readb(0xa40800a4); /* IMR9 */
990 sh7724_rstandby_state.imr10 = __raw_readb(0xa40800a8); /* IMR10 */
991 sh7724_rstandby_state.imr11 = __raw_readb(0xa40800ac); /* IMR11 */
992 sh7724_rstandby_state.imr12 = __raw_readb(0xa40800b0); /* IMR12 */
993
994 /* RWDT */
995 sh7724_rstandby_state.rwtcnt = __raw_readb(0xa4520000); /* RWTCNT */
996 sh7724_rstandby_state.rwtcnt |= 0x5a00;
997 sh7724_rstandby_state.rwtcsr = __raw_readb(0xa4520004); /* RWTCSR */
998 sh7724_rstandby_state.rwtcsr |= 0xa500;
999 __raw_writew(sh7724_rstandby_state.rwtcsr & 0x07, 0xa4520004);
1000
1001 return NOTIFY_DONE;
1002}
1003
1004static int sh7724_post_sleep_notifier_call(struct notifier_block *nb,
1005 unsigned long flags, void *unused)
1006{
1007 if (!(flags & SUSP_SH_RSTANDBY))
1008 return NOTIFY_DONE;
1009
1010 /* BCR */
1011 __raw_writel(sh7724_rstandby_state.mmselr, 0xff800020); /* MMSELR */
1012 __raw_writel(sh7724_rstandby_state.cs0bcr, 0xfec10004); /* CS0BCR */
1013 __raw_writel(sh7724_rstandby_state.cs4bcr, 0xfec10010); /* CS4BCR */
1014 __raw_writel(sh7724_rstandby_state.cs5abcr, 0xfec10014); /* CS5ABCR */
1015 __raw_writel(sh7724_rstandby_state.cs5bbcr, 0xfec10018); /* CS5BBCR */
1016 __raw_writel(sh7724_rstandby_state.cs6abcr, 0xfec1001c); /* CS6ABCR */
1017 __raw_writel(sh7724_rstandby_state.cs6bbcr, 0xfec10020); /* CS6BBCR */
1018 __raw_writel(sh7724_rstandby_state.cs4wcr, 0xfec10030); /* CS4WCR */
1019 __raw_writel(sh7724_rstandby_state.cs5awcr, 0xfec10034); /* CS5AWCR */
1020 __raw_writel(sh7724_rstandby_state.cs5bwcr, 0xfec10038); /* CS5BWCR */
1021 __raw_writel(sh7724_rstandby_state.cs6awcr, 0xfec1003c); /* CS6AWCR */
1022 __raw_writel(sh7724_rstandby_state.cs6bwcr, 0xfec10040); /* CS6BWCR */
1023
1024 /* INTC */
1025 __raw_writew(sh7724_rstandby_state.ipra, 0xa4080000); /* IPRA */
1026 __raw_writew(sh7724_rstandby_state.iprb, 0xa4080004); /* IPRB */
1027 __raw_writew(sh7724_rstandby_state.iprc, 0xa4080008); /* IPRC */
1028 __raw_writew(sh7724_rstandby_state.iprd, 0xa408000c); /* IPRD */
1029 __raw_writew(sh7724_rstandby_state.ipre, 0xa4080010); /* IPRE */
1030 __raw_writew(sh7724_rstandby_state.iprf, 0xa4080014); /* IPRF */
1031 __raw_writew(sh7724_rstandby_state.iprg, 0xa4080018); /* IPRG */
1032 __raw_writew(sh7724_rstandby_state.iprh, 0xa408001c); /* IPRH */
1033 __raw_writew(sh7724_rstandby_state.ipri, 0xa4080020); /* IPRI */
1034 __raw_writew(sh7724_rstandby_state.iprj, 0xa4080024); /* IPRJ */
1035 __raw_writew(sh7724_rstandby_state.iprk, 0xa4080028); /* IPRK */
1036 __raw_writew(sh7724_rstandby_state.iprl, 0xa408002c); /* IPRL */
1037 __raw_writeb(sh7724_rstandby_state.imr0, 0xa4080080); /* IMR0 */
1038 __raw_writeb(sh7724_rstandby_state.imr1, 0xa4080084); /* IMR1 */
1039 __raw_writeb(sh7724_rstandby_state.imr2, 0xa4080088); /* IMR2 */
1040 __raw_writeb(sh7724_rstandby_state.imr3, 0xa408008c); /* IMR3 */
1041 __raw_writeb(sh7724_rstandby_state.imr4, 0xa4080090); /* IMR4 */
1042 __raw_writeb(sh7724_rstandby_state.imr5, 0xa4080094); /* IMR5 */
1043 __raw_writeb(sh7724_rstandby_state.imr6, 0xa4080098); /* IMR6 */
1044 __raw_writeb(sh7724_rstandby_state.imr7, 0xa408009c); /* IMR7 */
1045 __raw_writeb(sh7724_rstandby_state.imr8, 0xa40800a0); /* IMR8 */
1046 __raw_writeb(sh7724_rstandby_state.imr9, 0xa40800a4); /* IMR9 */
1047 __raw_writeb(sh7724_rstandby_state.imr10, 0xa40800a8); /* IMR10 */
1048 __raw_writeb(sh7724_rstandby_state.imr11, 0xa40800ac); /* IMR11 */
1049 __raw_writeb(sh7724_rstandby_state.imr12, 0xa40800b0); /* IMR12 */
1050
1051 /* RWDT */
1052 __raw_writew(sh7724_rstandby_state.rwtcnt, 0xa4520000); /* RWTCNT */
1053 __raw_writew(sh7724_rstandby_state.rwtcsr, 0xa4520004); /* RWTCSR */
1054
1055 return NOTIFY_DONE;
1056}
1057
1058static struct notifier_block sh7724_pre_sleep_notifier = {
1059 .notifier_call = sh7724_pre_sleep_notifier_call,
1060 .priority = SH_MOBILE_PRE(SH_MOBILE_SLEEP_CPU),
1061};
1062
1063static struct notifier_block sh7724_post_sleep_notifier = {
1064 .notifier_call = sh7724_post_sleep_notifier_call,
1065 .priority = SH_MOBILE_POST(SH_MOBILE_SLEEP_CPU),
1066};
1067
1068static int __init sh7724_sleep_setup(void)
1069{
1070 atomic_notifier_chain_register(&sh_mobile_pre_sleep_notifier_list,
1071 &sh7724_pre_sleep_notifier);
1072
1073 atomic_notifier_chain_register(&sh_mobile_post_sleep_notifier_list,
1074 &sh7724_post_sleep_notifier);
1075 return 0;
1076}
1077arch_initcall(sh7724_sleep_setup);
1078
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index e848443deeb9..c7ba9166e18a 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -15,6 +15,15 @@
15#include <linux/sh_timer.h> 15#include <linux/sh_timer.h>
16#include <asm/mmzone.h> 16#include <asm/mmzone.h>
17 17
18/*
19 * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
20 * INTEVT values overlap with the FPU EXPEVT ones, requiring special
21 * demuxing in the exception dispatch path.
22 *
23 * As this overlap is something that never should have made it in to
24 * silicon in the first place, we just refuse to deal with the port at
25 * all rather than adding infrastructure to hack around it.
26 */
18static struct plat_sci_port sci_platform_data[] = { 27static struct plat_sci_port sci_platform_data[] = {
19 { 28 {
20 .mapbase = 0xffc30000, 29 .mapbase = 0xffc30000,
@@ -27,11 +36,6 @@ static struct plat_sci_port sci_platform_data[] = {
27 .type = PORT_SCIF, 36 .type = PORT_SCIF,
28 .irqs = { 44, 45, 47, 46 }, 37 .irqs = { 44, 45, 47, 46 },
29 }, { 38 }, {
30 .mapbase = 0xffc50000,
31 .flags = UPF_BOOT_AUTOCONF,
32 .type = PORT_SCIF,
33 .irqs = { 48, 49, 51, 50 },
34 }, {
35 .mapbase = 0xffc60000, 39 .mapbase = 0xffc60000,
36 .flags = UPF_BOOT_AUTOCONF, 40 .flags = UPF_BOOT_AUTOCONF,
37 .type = PORT_SCIF, 41 .type = PORT_SCIF,
@@ -268,7 +272,11 @@ enum {
268 UNUSED = 0, 272 UNUSED = 0,
269 273
270 /* interrupt sources */ 274 /* interrupt sources */
271 IRL, IRQ0, IRQ1, IRQ2, IRQ3, 275 IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
276 IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
277 IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
278 IRL_HHLL, IRL_HHLH, IRL_HHHL,
279 IRQ0, IRQ1, IRQ2, IRQ3,
272 HUDII, 280 HUDII,
273 TMU0, TMU1, TMU2, TMU3, TMU4, TMU5, 281 TMU0, TMU1, TMU2, TMU3, TMU4, TMU5,
274 PCII0, PCII1, PCII2, PCII3, PCII4, 282 PCII0, PCII1, PCII2, PCII3, PCII4,
@@ -291,7 +299,7 @@ enum {
291 INTICI4, INTICI5, INTICI6, INTICI7, 299 INTICI4, INTICI5, INTICI6, INTICI7,
292 300
293 /* interrupt groups */ 301 /* interrupt groups */
294 PCII56789, SCIF0, SCIF1, SCIF2, SCIF3, 302 IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
295 DMAC0, DMAC1, 303 DMAC0, DMAC1,
296}; 304};
297 305
@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = {
309 INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), 317 INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
310 INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), 318 INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
311 INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), 319 INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
312 INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820),
313 INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860),
314 INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0), 320 INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0),
315 INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0), 321 INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0),
316 INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920), 322 INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920),
@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = {
344}; 350};
345 351
346static struct intc_group groups[] __initdata = { 352static struct intc_group groups[] __initdata = {
353 INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
354 IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
355 IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
356 IRL_HHLL, IRL_HHLH, IRL_HHHL),
347 INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9), 357 INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9),
348 INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), 358 INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
349 INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), 359 INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
350 INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
351 INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI), 360 INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI),
352 INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, 361 INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
353 DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), 362 DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
419 428
420/* External interrupt pins in IRL mode */ 429/* External interrupt pins in IRL mode */
421static struct intc_vect vectors_irl[] __initdata = { 430static struct intc_vect vectors_irl[] __initdata = {
422 INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220), 431 INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
423 INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260), 432 INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
424 INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0), 433 INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
425 INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0), 434 INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
426 INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320), 435 INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
427 INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360), 436 INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
428 INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0), 437 INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
429 INTC_VECT(IRL, 0x3c0), 438 INTC_VECT(IRL_HHHL, 0x3c0),
430}; 439};
431 440
432static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups, 441static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
index 185ec3976a25..5863e0c4d02f 100644
--- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -14,6 +14,13 @@
14#include <linux/interrupt.h> 14#include <linux/interrupt.h>
15#include <linux/io.h> 15#include <linux/io.h>
16 16
17#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
18#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
19
20#define STBCR_MSTP 0x00000001
21#define STBCR_RESET 0x00000002
22#define STBCR_LTSLP 0x80000000
23
17static irqreturn_t ipi_interrupt_handler(int irq, void *arg) 24static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
18{ 25{
19 unsigned int message = (unsigned int)(long)arg; 26 unsigned int message = (unsigned int)(long)arg;
@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
21 unsigned int offs = 4 * cpu; 28 unsigned int offs = 4 * cpu;
22 unsigned int x; 29 unsigned int x;
23 30
24 x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ 31 x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
25 x &= (1 << (message << 2)); 32 x &= (1 << (message << 2));
26 ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ 33 __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
27 34
28 smp_message_recv(message); 35 smp_message_recv(message);
29 36
@@ -37,6 +44,9 @@ void __init plat_smp_setup(void)
37 44
38 init_cpu_possible(cpumask_of(cpu)); 45 init_cpu_possible(cpumask_of(cpu));
39 46
47 /* Enable light sleep for the boot CPU */
48 __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));
49
40 __cpu_number_map[0] = 0; 50 __cpu_number_map[0] = 0;
41 __cpu_logical_map[0] = 0; 51 __cpu_logical_map[0] = 0;
42 52
@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
66 "IPI", (void *)(long)i); 76 "IPI", (void *)(long)i);
67} 77}
68 78
69#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
70#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
71
72#define STBCR_MSTP 0x00000001
73#define STBCR_RESET 0x00000002
74#define STBCR_LTSLP 0x80000000
75
76#define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP)
77
78void plat_start_cpu(unsigned int cpu, unsigned long entry_point) 79void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
79{ 80{
80 ctrl_outl(entry_point, RESET_REG(cpu)); 81 __raw_writel(entry_point, RESET_REG(cpu));
81 82
82 if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 83 if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
83 ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); 84 __raw_writel(STBCR_MSTP, STBCR_REG(cpu));
84 85
85 while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) 86 while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
86 cpu_relax(); 87 cpu_relax();
87 88
88 /* Start up secondary processor by sending a reset */ 89 /* Start up secondary processor by sending a reset */
89 ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); 90 __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));
90} 91}
91 92
92int plat_smp_processor_id(void) 93int plat_smp_processor_id(void)
93{ 94{
94 return ctrl_inl(0xff000048); /* CPIDR */ 95 return __raw_readl(0xff000048); /* CPIDR */
95} 96}
96 97
97void plat_send_ipi(unsigned int cpu, unsigned int message) 98void plat_send_ipi(unsigned int cpu, unsigned int message)
@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message)
100 101
101 BUG_ON(cpu >= 4); 102 BUG_ON(cpu >= 4);
102 103
103 ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ 104 __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
104} 105}
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b0aacf675258..8f13f73cb2cb 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
933 933
934 pta restore_all, tr1 934 pta restore_all, tr1
935 935
936 movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8 936 movi _TIF_SIGPENDING, r8
937 and r8, r7, r8 937 and r8, r7, r8
938 pta work_notifysig, tr0 938 pta work_notifysig, tr0
939 bne r8, ZERO, tr0 939 bne r8, ZERO, tr0
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 1c504bd972c3..83972aa319c2 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -87,25 +87,31 @@ void sh_mobile_setup_cpuidle(void)
87 87
88 dev->safe_state = state; 88 dev->safe_state = state;
89 89
90 state = &dev->states[i++]; 90 if (sh_mobile_sleep_supported & SUSP_SH_SF) {
91 snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); 91 state = &dev->states[i++];
92 strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN); 92 snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
93 state->exit_latency = 100; 93 strncpy(state->desc, "SuperH Sleep Mode [SF]",
94 state->target_residency = 1 * 2; 94 CPUIDLE_DESC_LEN);
95 state->power_usage = 1; 95 state->exit_latency = 100;
96 state->flags = 0; 96 state->target_residency = 1 * 2;
97 state->flags |= CPUIDLE_FLAG_TIME_VALID; 97 state->power_usage = 1;
98 state->enter = cpuidle_sleep_enter; 98 state->flags = 0;
99 state->flags |= CPUIDLE_FLAG_TIME_VALID;
100 state->enter = cpuidle_sleep_enter;
101 }
99 102
100 state = &dev->states[i++]; 103 if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
101 snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); 104 state = &dev->states[i++];
102 strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN); 105 snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
103 state->exit_latency = 2300; 106 strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
104 state->target_residency = 1 * 2; 107 CPUIDLE_DESC_LEN);
105 state->power_usage = 1; 108 state->exit_latency = 2300;
106 state->flags = 0; 109 state->target_residency = 1 * 2;
107 state->flags |= CPUIDLE_FLAG_TIME_VALID; 110 state->power_usage = 1;
108 state->enter = cpuidle_sleep_enter; 111 state->flags = 0;
112 state->flags |= CPUIDLE_FLAG_TIME_VALID;
113 state->enter = cpuidle_sleep_enter;
114 }
109 115
110 dev->state_count = i; 116 dev->state_count = i;
111 117
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index ee3c2aaf66fb..ca029a44743c 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -15,6 +15,13 @@
15#include <linux/suspend.h> 15#include <linux/suspend.h>
16#include <asm/suspend.h> 16#include <asm/suspend.h>
17#include <asm/uaccess.h> 17#include <asm/uaccess.h>
18#include <asm/cacheflush.h>
19
20/*
21 * Notifier lists for pre/post sleep notification
22 */
23ATOMIC_NOTIFIER_HEAD(sh_mobile_pre_sleep_notifier_list);
24ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list);
18 25
19/* 26/*
20 * Sleep modes available on SuperH Mobile: 27 * Sleep modes available on SuperH Mobile:
@@ -26,30 +33,105 @@
26#define SUSP_MODE_SLEEP (SUSP_SH_SLEEP) 33#define SUSP_MODE_SLEEP (SUSP_SH_SLEEP)
27#define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF) 34#define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF)
28#define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF) 35#define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF)
36#define SUSP_MODE_RSTANDBY (SUSP_SH_RSTANDBY | SUSP_SH_MMU | SUSP_SH_SF)
37 /*
38 * U-standby mode is unsupported since it needs bootloader hacks
39 */
29 40
30/* 41#ifdef CONFIG_CPU_SUBTYPE_SH7724
31 * The following modes are not there yet: 42#define RAM_BASE 0xfd800000 /* RSMEM */
32 * 43#else
33 * R-standby mode is unsupported, but will be added in the future 44#define RAM_BASE 0xe5200000 /* ILRAM */
34 * U-standby mode is low priority since it needs bootloader hacks 45#endif
35 */
36
37#define ILRAM_BASE 0xe5200000
38
39extern const unsigned char sh_mobile_standby[];
40extern const unsigned int sh_mobile_standby_size;
41 46
42void sh_mobile_call_standby(unsigned long mode) 47void sh_mobile_call_standby(unsigned long mode)
43{ 48{
44 void *onchip_mem = (void *)ILRAM_BASE; 49 void *onchip_mem = (void *)RAM_BASE;
45 void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem; 50 struct sh_sleep_data *sdp = onchip_mem;
51 void (*standby_onchip_mem)(unsigned long, unsigned long);
52
53 /* code located directly after data structure */
54 standby_onchip_mem = (void *)(sdp + 1);
55
56 atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list,
57 mode, NULL);
58
59 /* flush the caches if MMU flag is set */
60 if (mode & SUSP_SH_MMU)
61 flush_cache_all();
46 62
47 /* Let assembly snippet in on-chip memory handle the rest */ 63 /* Let assembly snippet in on-chip memory handle the rest */
48 standby_onchip_mem(mode, ILRAM_BASE); 64 standby_onchip_mem(mode, RAM_BASE);
65
66 atomic_notifier_call_chain(&sh_mobile_post_sleep_notifier_list,
67 mode, NULL);
68}
69
70extern char sh_mobile_sleep_enter_start;
71extern char sh_mobile_sleep_enter_end;
72
73extern char sh_mobile_sleep_resume_start;
74extern char sh_mobile_sleep_resume_end;
75
76unsigned long sh_mobile_sleep_supported = SUSP_SH_SLEEP;
77
78void sh_mobile_register_self_refresh(unsigned long flags,
79 void *pre_start, void *pre_end,
80 void *post_start, void *post_end)
81{
82 void *onchip_mem = (void *)RAM_BASE;
83 void *vp;
84 struct sh_sleep_data *sdp;
85 int n;
86
87 /* part 0: data area */
88 sdp = onchip_mem;
89 sdp->addr.stbcr = 0xa4150020; /* STBCR */
90 sdp->addr.bar = 0xa4150040; /* BAR */
91 sdp->addr.pteh = 0xff000000; /* PTEH */
92 sdp->addr.ptel = 0xff000004; /* PTEL */
93 sdp->addr.ttb = 0xff000008; /* TTB */
94 sdp->addr.tea = 0xff00000c; /* TEA */
95 sdp->addr.mmucr = 0xff000010; /* MMUCR */
96 sdp->addr.ptea = 0xff000034; /* PTEA */
97 sdp->addr.pascr = 0xff000070; /* PASCR */
98 sdp->addr.irmcr = 0xff000078; /* IRMCR */
99 sdp->addr.ccr = 0xff00001c; /* CCR */
100 sdp->addr.ramcr = 0xff000074; /* RAMCR */
101 vp = sdp + 1;
102
103 /* part 1: common code to enter sleep mode */
104 n = &sh_mobile_sleep_enter_end - &sh_mobile_sleep_enter_start;
105 memcpy(vp, &sh_mobile_sleep_enter_start, n);
106 vp += roundup(n, 4);
107
108 /* part 2: board specific code to enter self-refresh mode */
109 n = pre_end - pre_start;
110 memcpy(vp, pre_start, n);
111 sdp->sf_pre = (unsigned long)vp;
112 vp += roundup(n, 4);
113
114 /* part 3: board specific code to resume from self-refresh mode */
115 n = post_end - post_start;
116 memcpy(vp, post_start, n);
117 sdp->sf_post = (unsigned long)vp;
118 vp += roundup(n, 4);
119
120 /* part 4: common code to resume from sleep mode */
121 WARN_ON(vp > (onchip_mem + 0x600));
122 vp = onchip_mem + 0x600; /* located at interrupt vector */
123 n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start;
124 memcpy(vp, &sh_mobile_sleep_resume_start, n);
125 sdp->resume = (unsigned long)vp;
126
127 sh_mobile_sleep_supported |= flags;
49} 128}
50 129
51static int sh_pm_enter(suspend_state_t state) 130static int sh_pm_enter(suspend_state_t state)
52{ 131{
132 if (!(sh_mobile_sleep_supported & SUSP_MODE_STANDBY_SF))
133 return -ENXIO;
134
53 local_irq_disable(); 135 local_irq_disable();
54 set_bl_bit(); 136 set_bl_bit();
55 sh_mobile_call_standby(SUSP_MODE_STANDBY_SF); 137 sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
@@ -65,13 +147,6 @@ static struct platform_suspend_ops sh_pm_ops = {
65 147
66static int __init sh_pm_init(void) 148static int __init sh_pm_init(void)
67{ 149{
68 void *onchip_mem = (void *)ILRAM_BASE;
69
70 /* Copy the assembly snippet to the otherwise ununsed ILRAM */
71 memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
72 wmb();
73 ctrl_barrier();
74
75 suspend_set_ops(&sh_pm_ops); 150 suspend_set_ops(&sh_pm_ops);
76 sh_mobile_setup_cpuidle(); 151 sh_mobile_setup_cpuidle();
77 return 0; 152 return 0;
diff --git a/arch/sh/kernel/cpu/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S
index a439e6c7824f..e9dd7fa0abd2 100644
--- a/arch/sh/kernel/cpu/shmobile/sleep.S
+++ b/arch/sh/kernel/cpu/shmobile/sleep.S
@@ -20,79 +20,103 @@
20 * Kernel mode register usage, see entry.S: 20 * Kernel mode register usage, see entry.S:
21 * k0 scratch 21 * k0 scratch
22 * k1 scratch 22 * k1 scratch
23 * k4 scratch
24 */ 23 */
25#define k0 r0 24#define k0 r0
26#define k1 r1 25#define k1 r1
27#define k4 r4
28 26
29/* manage self-refresh and enter standby mode. 27/* manage self-refresh and enter standby mode. must be self-contained.
30 * this code will be copied to on-chip memory and executed from there. 28 * this code will be copied to on-chip memory and executed from there.
31 */ 29 */
30 .balign 4
31ENTRY(sh_mobile_sleep_enter_start)
32 32
33 .balign 4096,0,4096 33 /* save mode flags */
34ENTRY(sh_mobile_standby) 34 mov.l r4, @(SH_SLEEP_MODE, r5)
35 35
36 /* save original vbr */ 36 /* save original vbr */
37 stc vbr, r1 37 stc vbr, r0
38 mova saved_vbr, r0 38 mov.l r0, @(SH_SLEEP_VBR, r5)
39 mov.l r1, @r0
40 39
41 /* point vbr to our on-chip memory page */ 40 /* point vbr to our on-chip memory page */
42 ldc r5, vbr 41 ldc r5, vbr
43 42
44 /* save return address */ 43 /* save return address */
45 mova saved_spc, r0 44 sts pr, r0
46 sts pr, r5 45 mov.l r0, @(SH_SLEEP_SPC, r5)
47 mov.l r5, @r0
48 46
49 /* save sr */ 47 /* save sr */
50 mova saved_sr, r0 48 stc sr, r0
51 stc sr, r5 49 mov.l r0, @(SH_SLEEP_SR, r5)
52 mov.l r5, @r0
53 50
54 /* save mode flags */ 51 /* save sp */
55 mova saved_mode, r0 52 mov.l r15, @(SH_SLEEP_SP, r5)
56 mov.l r4, @r0 53
54 /* save stbcr */
55 bsr save_register
56 mov #SH_SLEEP_REG_STBCR, r0
57
58 /* save mmu and cache context if needed */
59 mov.l @(SH_SLEEP_MODE, r5), r0
60 tst #SUSP_SH_MMU, r0
61 bt skip_mmu_save_disable
62
63 /* save mmu state */
64 bsr save_register
65 mov #SH_SLEEP_REG_PTEH, r0
66
67 bsr save_register
68 mov #SH_SLEEP_REG_PTEL, r0
69
70 bsr save_register
71 mov #SH_SLEEP_REG_TTB, r0
72
73 bsr save_register
74 mov #SH_SLEEP_REG_TEA, r0
75
76 bsr save_register
77 mov #SH_SLEEP_REG_MMUCR, r0
78
79 bsr save_register
80 mov #SH_SLEEP_REG_PTEA, r0
81
82 bsr save_register
83 mov #SH_SLEEP_REG_PASCR, r0
57 84
58 /* put mode flags in r0 */ 85 bsr save_register
59 mov r4, r0 86 mov #SH_SLEEP_REG_IRMCR, r0
60 87
88 /* invalidate TLBs and disable the MMU */
89 bsr get_register
90 mov #SH_SLEEP_REG_MMUCR, r0
91 mov #4, r1
92 mov.l r1, @r0
93 icbi @r0
94
95 /* save cache registers and disable caches */
96 bsr save_register
97 mov #SH_SLEEP_REG_CCR, r0
98
99 bsr save_register
100 mov #SH_SLEEP_REG_RAMCR, r0
101
102 bsr get_register
103 mov #SH_SLEEP_REG_CCR, r0
104 mov #0, r1
105 mov.l r1, @r0
106 icbi @r0
107
108skip_mmu_save_disable:
109 /* call self-refresh entering code if needed */
110 mov.l @(SH_SLEEP_MODE, r5), r0
61 tst #SUSP_SH_SF, r0 111 tst #SUSP_SH_SF, r0
62 bt skip_set_sf 112 bt skip_set_sf
63#ifdef CONFIG_CPU_SUBTYPE_SH7724 113
64 /* DBSC: put memory in self-refresh mode */ 114 mov.l @(SH_SLEEP_SF_PRE, r5), r0
65 mov.l dben_reg, r4 115 jsr @r0
66 mov.l dben_data0, r1 116 nop
67 mov.l r1, @r4
68
69 mov.l dbrfpdn0_reg, r4
70 mov.l dbrfpdn0_data0, r1
71 mov.l r1, @r4
72
73 mov.l dbcmdcnt_reg, r4
74 mov.l dbcmdcnt_data0, r1
75 mov.l r1, @r4
76
77 mov.l dbcmdcnt_reg, r4
78 mov.l dbcmdcnt_data1, r1
79 mov.l r1, @r4
80
81 mov.l dbrfpdn0_reg, r4
82 mov.l dbrfpdn0_data1, r1
83 mov.l r1, @r4
84#else
85 /* SBSC: disable power down and put in self-refresh mode */
86 mov.l 1f, r4
87 mov.l 2f, r1
88 mov.l @r4, r2
89 or r1, r2
90 mov.l 3f, r3
91 and r3, r2
92 mov.l r2, @r4
93#endif
94 117
95skip_set_sf: 118skip_set_sf:
119 mov.l @(SH_SLEEP_MODE, r5), r0
96 tst #SUSP_SH_STANDBY, r0 120 tst #SUSP_SH_STANDBY, r0
97 bt test_rstandby 121 bt test_rstandby
98 122
@@ -104,6 +128,12 @@ test_rstandby:
104 tst #SUSP_SH_RSTANDBY, r0 128 tst #SUSP_SH_RSTANDBY, r0
105 bt test_ustandby 129 bt test_ustandby
106 130
131 /* setup BAR register */
132 bsr get_register
133 mov #SH_SLEEP_REG_BAR, r0
134 mov.l @(SH_SLEEP_RESUME, r5), r1
135 mov.l r1, @r0
136
107 /* set mode to "r-standby mode" */ 137 /* set mode to "r-standby mode" */
108 bra do_sleep 138 bra do_sleep
109 mov #0x20, r1 139 mov #0x20, r1
@@ -123,124 +153,136 @@ force_sleep:
123 153
124do_sleep: 154do_sleep:
125 /* setup and enter selected standby mode */ 155 /* setup and enter selected standby mode */
126 mov.l 5f, r4 156 bsr get_register
127 mov.l r1, @r4 157 mov #SH_SLEEP_REG_STBCR, r0
158 mov.l r1, @r0
128again: 159again:
129 sleep 160 sleep
130 bra again 161 bra again
131 nop 162 nop
132 163
133restore_jump_vbr: 164save_register:
165 add #SH_SLEEP_BASE_ADDR, r0
166 mov.l @(r0, r5), r1
167 add #-SH_SLEEP_BASE_ADDR, r0
168 mov.l @r1, r1
169 add #SH_SLEEP_BASE_DATA, r0
170 mov.l r1, @(r0, r5)
171 add #-SH_SLEEP_BASE_DATA, r0
172 rts
173 nop
174
175get_register:
176 add #SH_SLEEP_BASE_ADDR, r0
177 mov.l @(r0, r5), r0
178 rts
179 nop
180ENTRY(sh_mobile_sleep_enter_end)
181
182 .balign 4
183ENTRY(sh_mobile_sleep_resume_start)
184
185 /* figure out start address */
186 bsr 0f
187 nop
1880:
189 sts pr, k1
190 mov.l 1f, k0
191 and k0, k1
192
193 /* store pointer to data area in VBR */
194 ldc k1, vbr
195
196 /* setup sr with saved sr */
197 mov.l @(SH_SLEEP_SR, k1), k0
198 ldc k0, sr
199
200 /* now: user register set! */
201 stc vbr, r5
202
134 /* setup spc with return address to c code */ 203 /* setup spc with return address to c code */
135 mov.l saved_spc, k0 204 mov.l @(SH_SLEEP_SPC, r5), r0
136 ldc k0, spc 205 ldc r0, spc
137 206
138 /* restore vbr */ 207 /* restore vbr */
139 mov.l saved_vbr, k0 208 mov.l @(SH_SLEEP_VBR, r5), r0
140 ldc k0, vbr 209 ldc r0, vbr
141 210
142 /* setup ssr with saved sr */ 211 /* setup ssr with saved sr */
143 mov.l saved_sr, k0 212 mov.l @(SH_SLEEP_SR, r5), r0
144 ldc k0, ssr 213 ldc r0, ssr
145 214
146 /* get mode flags */ 215 /* restore sp */
147 mov.l saved_mode, k0 216 mov.l @(SH_SLEEP_SP, r5), r15
148 217
149done_sleep: 218 /* restore sleep mode register */
150 /* reset standby mode to sleep mode */ 219 bsr restore_register
151 mov.l 5f, k4 220 mov #SH_SLEEP_REG_STBCR, r0
152 mov #0x00, k1
153 mov.l k1, @k4
154 221
155 tst #SUSP_SH_SF, k0 222 /* call self-refresh resume code if needed */
223 mov.l @(SH_SLEEP_MODE, r5), r0
224 tst #SUSP_SH_SF, r0
156 bt skip_restore_sf 225 bt skip_restore_sf
157 226
158#ifdef CONFIG_CPU_SUBTYPE_SH7724 227 mov.l @(SH_SLEEP_SF_POST, r5), r0
159 /* DBSC: put memory in auto-refresh mode */ 228 jsr @r0
160 mov.l dbrfpdn0_reg, k4 229 nop
161 mov.l dbrfpdn0_data0, k1 230
162 mov.l k1, @k4
163
164 nop /* sleep 140 ns */
165 nop
166 nop
167 nop
168
169 mov.l dbcmdcnt_reg, k4
170 mov.l dbcmdcnt_data0, k1
171 mov.l k1, @k4
172
173 mov.l dbcmdcnt_reg, k4
174 mov.l dbcmdcnt_data1, k1
175 mov.l k1, @k4
176
177 mov.l dben_reg, k4
178 mov.l dben_data1, k1
179 mov.l k1, @k4
180
181 mov.l dbrfpdn0_reg, k4
182 mov.l dbrfpdn0_data2, k1
183 mov.l k1, @k4
184#else
185 /* SBSC: set auto-refresh mode */
186 mov.l 1f, k4
187 mov.l @k4, k0
188 mov.l 4f, k1
189 and k1, k0
190 mov.l k0, @k4
191 mov.l 6f, k4
192 mov.l 8f, k0
193 mov.l @k4, k1
194 mov #-1, k4
195 add k4, k1
196 or k1, k0
197 mov.l 7f, k1
198 mov.l k0, @k1
199#endif
200skip_restore_sf: 231skip_restore_sf:
201 /* jump to vbr vector */ 232 /* restore mmu and cache state if needed */
202 mov.l saved_vbr, k0 233 mov.l @(SH_SLEEP_MODE, r5), r0
203 mov.l offset_vbr, k4 234 tst #SUSP_SH_MMU, r0
204 add k4, k0 235 bt skip_restore_mmu
205 jmp @k0 236
237 /* restore mmu state */
238 bsr restore_register
239 mov #SH_SLEEP_REG_PTEH, r0
240
241 bsr restore_register
242 mov #SH_SLEEP_REG_PTEL, r0
243
244 bsr restore_register
245 mov #SH_SLEEP_REG_TTB, r0
246
247 bsr restore_register
248 mov #SH_SLEEP_REG_TEA, r0
249
250 bsr restore_register
251 mov #SH_SLEEP_REG_PTEA, r0
252
253 bsr restore_register
254 mov #SH_SLEEP_REG_PASCR, r0
255
256 bsr restore_register
257 mov #SH_SLEEP_REG_IRMCR, r0
258
259 bsr restore_register
260 mov #SH_SLEEP_REG_MMUCR, r0
261 icbi @r0
262
263 /* restore cache settings */
264 bsr restore_register
265 mov #SH_SLEEP_REG_RAMCR, r0
266 icbi @r0
267
268 bsr restore_register
269 mov #SH_SLEEP_REG_CCR, r0
270 icbi @r0
271
272skip_restore_mmu:
273 rte
206 nop 274 nop
207 275
208 .balign 4 276restore_register:
209saved_mode: .long 0 277 add #SH_SLEEP_BASE_DATA, r0
210saved_spc: .long 0 278 mov.l @(r0, r5), r1
211saved_sr: .long 0 279 add #-SH_SLEEP_BASE_DATA, r0
212saved_vbr: .long 0 280 add #SH_SLEEP_BASE_ADDR, r0
213offset_vbr: .long 0x600 281 mov.l @(r0, r5), r0
214#ifdef CONFIG_CPU_SUBTYPE_SH7724 282 mov.l r1, @r0
215dben_reg: .long 0xfd000010 /* DBEN */ 283 rts
216dben_data0: .long 0
217dben_data1: .long 1
218dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */
219dbrfpdn0_data0: .long 0
220dbrfpdn0_data1: .long 1
221dbrfpdn0_data2: .long 0x00010000
222dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */
223dbcmdcnt_data0: .long 2
224dbcmdcnt_data1: .long 4
225#else
2261: .long 0xfe400008 /* SDCR0 */
2272: .long 0x00000400
2283: .long 0xffff7fff
2294: .long 0xfffffbff
230#endif
2315: .long 0xa4150020 /* STBCR */
2326: .long 0xfe40001c /* RTCOR */
2337: .long 0xfe400018 /* RTCNT */
2348: .long 0xa55a0000
235
236
237/* interrupt vector @ 0x600 */
238 .balign 0x400,0,0x400
239 .long 0xdeadbeef
240 .balign 0x200,0,0x200
241 bra restore_jump_vbr
242 nop 284 nop
243sh_mobile_standby_end:
244 285
245ENTRY(sh_mobile_standby_size) 286 .balign 4
246 .long sh_mobile_standby_end - sh_mobile_standby 2871: .long ~0x7ff
288ENTRY(sh_mobile_sleep_resume_end)
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
deleted file mode 100644
index 81923079fa12..000000000000
--- a/arch/sh/kernel/cpu/ubc.S
+++ /dev/null
@@ -1,59 +0,0 @@
1/*
2 * arch/sh/kernel/cpu/ubc.S
3 *
4 * Set of management routines for the User Break Controller (UBC)
5 *
6 * Copyright (C) 2002 Paul Mundt
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13#include <linux/linkage.h>
14#include <asm/ubc.h>
15
16#define STBCR2 0xffc00010
17
18ENTRY(ubc_sleep)
19 mov #0, r0
20
21 mov.l 1f, r1 ! Zero out UBC_BBRA ..
22 mov.w r0, @r1
23
24 mov.l 2f, r1 ! .. same for BBRB ..
25 mov.w r0, @r1
26
27 mov.l 3f, r1 ! .. and again for BRCR.
28 mov.w r0, @r1
29
30 mov.w @r1, r0 ! Dummy read BRCR
31
32 mov.l 4f, r1 ! Set MSTP5 in STBCR2
33 mov.b @r1, r0
34 or #0x01, r0
35 mov.b r0, @r1
36
37 mov.b @r1, r0 ! Two dummy reads ..
38 mov.b @r1, r0
39
40 rts
41 nop
42
43ENTRY(ubc_wakeup)
44 mov.l 4f, r1 ! Clear MSTP5
45 mov.b @r1, r0
46 and #0xfe, r0
47 mov.b r0, @r1
48
49 mov.b @r1, r0 ! Two more dummy reads ..
50 mov.b @r1, r0
51
52 rts
53 nop
54
551: .long UBC_BBRA
562: .long UBC_BBRB
573: .long UBC_BRCR
584: .long STBCR2
59