1
2
3
4
5
6
7
8
9#include <linux/init.h>
10#include <linux/mman.h>
11#include <linux/mm.h>
12#include <linux/threads.h>
13#include <asm/addrspace.h>
14#include <asm/page.h>
15#include <asm/pgtable.h>
16#include <asm/processor.h>
17#include <asm/cache.h>
18#include <asm/io.h>
19#include <asm/uaccess.h>
20#include <asm/pgalloc.h>
21#include <asm/mmu_context.h>
22
23
24#define CCR 0xffffffec
25
26#define CCR_CACHE_CE 0x01
27#define CCR_CACHE_WT 0x02
28#define CCR_CACHE_CB 0x04
29#define CCR_CACHE_CF 0x08
30#define CCR_CACHE_RA 0x20
31
32#define CCR_CACHE_VAL (CCR_CACHE_CB|CCR_CACHE_CE)
33#define CCR_CACHE_INIT (CCR_CACHE_CF|CCR_CACHE_VAL)
34
35#define CACHE_OC_ADDRESS_ARRAY 0xf0000000
36#define CACHE_VALID 1
37#define CACHE_UPDATED 2
38#define CACHE_PHYSADDR_MASK 0x1ffffc00
39
40
41
42struct _cache_system_info {
43 int way_shift;
44 int entry_mask;
45 int num_entries;
46};
47
48
49
50
51static struct _cache_system_info cache_system_info = {0,};
52
53#define CACHE_OC_WAY_SHIFT (cache_system_info.way_shift)
54#define CACHE_OC_ENTRY_SHIFT 4
55#define CACHE_OC_ENTRY_MASK (cache_system_info.entry_mask)
56#define CACHE_OC_NUM_ENTRIES (cache_system_info.num_entries)
57#define CACHE_OC_NUM_WAYS 4
58#define CACHE_OC_ASSOC_BIT (1<<3)
59
60
61
62
63
64
65
66
67
68
69
70static inline void cache_wback_all(void)
71{
72 unsigned long addr, data, i, j;
73
74 for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) {
75 for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
76 addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
77 (i<<CACHE_OC_ENTRY_SHIFT);
78 data = ctrl_inl(addr);
79 if ((data & (CACHE_UPDATED|CACHE_VALID))
80 == (CACHE_UPDATED|CACHE_VALID))
81 ctrl_outl(data & ~CACHE_UPDATED, addr);
82 }
83 }
84}
85
86static void __init
87detect_cpu_and_cache_system(void)
88{
89 unsigned long addr0, addr1, data0, data1, data2, data3;
90
91 jump_to_P2();
92
93
94
95
96
97 addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
98 addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
99
100
101 data0 = ctrl_inl(addr0);
102 ctrl_outl(data0&~(CACHE_VALID|CACHE_UPDATED), addr0);
103 data1 = ctrl_inl(addr1);
104 ctrl_outl(data1&~(CACHE_VALID|CACHE_UPDATED), addr1);
105
106
107 data0 = ctrl_inl(addr0);
108 data0 ^= CACHE_VALID;
109 ctrl_outl(data0, addr0);
110 data1 = ctrl_inl(addr1);
111 data2 = data1 ^ CACHE_VALID;
112 ctrl_outl(data2, addr1);
113 data3 = ctrl_inl(addr0);
114
115
116 ctrl_outl(data0&~CACHE_VALID, addr0);
117 ctrl_outl(data2&~CACHE_VALID, addr1);
118 back_to_P1();
119
120 if (data0 == data1 && data2 == data3) {
121 cache_system_info.way_shift = 11;
122 cache_system_info.entry_mask = 0x7f0;
123 cache_system_info.num_entries = 128;
124 cpu_data->type = CPU_SH7708;
125 } else {
126 cache_system_info.way_shift = 12;
127 cache_system_info.entry_mask = 0xff0;
128 cache_system_info.num_entries = 256;
129 cpu_data->type = CPU_SH7729;
130 }
131}
132
133void __init cache_init(void)
134{
135 unsigned long ccr;
136
137 detect_cpu_and_cache_system();
138
139 jump_to_P2();
140 ccr = ctrl_inl(CCR);
141 if (ccr & CCR_CACHE_CE)
142
143
144
145
146 cache_wback_all();
147
148 ctrl_outl(CCR_CACHE_INIT, CCR);
149 back_to_P1();
150}
151
152
153
154
155
156
157
158
159
160
161
162void __flush_wback_region(void *start, int size)
163{
164 unsigned long v, j;
165 unsigned long begin, end;
166 unsigned long flags;
167
168 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
169 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
170 & ~(L1_CACHE_BYTES-1);
171
172 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
173 for (j=0; j<CACHE_OC_NUM_WAYS; j++) {
174 unsigned long data, addr, p;
175
176 p = __pa(v);
177 addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)|
178 (v&CACHE_OC_ENTRY_MASK);
179 save_and_cli(flags);
180 data = ctrl_inl(addr);
181
182 if ((data & CACHE_PHYSADDR_MASK) ==
183 (p & CACHE_PHYSADDR_MASK)) {
184 data &= ~CACHE_UPDATED;
185 ctrl_outl(data, addr);
186 restore_flags(flags);
187 break;
188 }
189 restore_flags(flags);
190 }
191 }
192}
193
194
195
196
197
198
199
200void __flush_purge_region(void *start, int size)
201{
202 unsigned long v;
203 unsigned long begin, end;
204
205 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
206 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
207 & ~(L1_CACHE_BYTES-1);
208
209 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
210 unsigned long data, addr;
211
212 data = (v & 0xfffffc00);
213 addr = CACHE_OC_ADDRESS_ARRAY | (v&CACHE_OC_ENTRY_MASK) |
214 CACHE_OC_ASSOC_BIT;
215 ctrl_outl(data, addr);
216 }
217}
218
219
220
221
222
223
224
225void __flush_invalidate_region(void *start, int size)
226 __attribute__((alias("__flush_purge_region")));
227