Root/
Source at commit 694c7fbe86b8a9c91392e505afcb9fcfc91deccc created 12 years 8 months ago. By Maarten ter Huurne, MIPS: JZ4740: Add cpufreq support | |
---|---|
1 | /* |
2 | * sc-rm7k.c: RM7000 cache management functions. |
3 | * |
4 | * Copyright (C) 1997, 2001, 2003, 2004 Ralf Baechle (ralf@linux-mips.org) |
5 | */ |
6 | |
7 | #undef DEBUG |
8 | |
9 | #include <linux/init.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/mm.h> |
12 | #include <linux/bitops.h> |
13 | |
14 | #include <asm/addrspace.h> |
15 | #include <asm/bcache.h> |
16 | #include <asm/cacheops.h> |
17 | #include <asm/mipsregs.h> |
18 | #include <asm/processor.h> |
19 | #include <asm/sections.h> |
20 | #include <asm/cacheflush.h> /* for run_uncached() */ |
21 | |
22 | /* Primary cache parameters. */ |
23 | #define sc_lsize 32 |
24 | #define tc_pagesize (32*128) |
25 | |
26 | /* Secondary cache parameters. */ |
27 | #define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ |
28 | |
29 | /* Tertiary cache parameters */ |
30 | #define tc_lsize 32 |
31 | |
32 | extern unsigned long icache_way_size, dcache_way_size; |
33 | static unsigned long tcache_size; |
34 | |
35 | #include <asm/r4kcache.h> |
36 | |
37 | static int rm7k_tcache_init; |
38 | |
39 | /* |
40 | * Writeback and invalidate the primary cache dcache before DMA. |
41 | * (XXX These need to be fixed ...) |
42 | */ |
43 | static void rm7k_sc_wback_inv(unsigned long addr, unsigned long size) |
44 | { |
45 | unsigned long end, a; |
46 | |
47 | pr_debug("rm7k_sc_wback_inv[%08lx,%08lx]", addr, size); |
48 | |
49 | /* Catch bad driver code */ |
50 | BUG_ON(size == 0); |
51 | |
52 | blast_scache_range(addr, addr + size); |
53 | |
54 | if (!rm7k_tcache_init) |
55 | return; |
56 | |
57 | a = addr & ~(tc_pagesize - 1); |
58 | end = (addr + size - 1) & ~(tc_pagesize - 1); |
59 | while(1) { |
60 | invalidate_tcache_page(a); /* Page_Invalidate_T */ |
61 | if (a == end) |
62 | break; |
63 | a += tc_pagesize; |
64 | } |
65 | } |
66 | |
67 | static void rm7k_sc_inv(unsigned long addr, unsigned long size) |
68 | { |
69 | unsigned long end, a; |
70 | |
71 | pr_debug("rm7k_sc_inv[%08lx,%08lx]", addr, size); |
72 | |
73 | /* Catch bad driver code */ |
74 | BUG_ON(size == 0); |
75 | |
76 | blast_inv_scache_range(addr, addr + size); |
77 | |
78 | if (!rm7k_tcache_init) |
79 | return; |
80 | |
81 | a = addr & ~(tc_pagesize - 1); |
82 | end = (addr + size - 1) & ~(tc_pagesize - 1); |
83 | while(1) { |
84 | invalidate_tcache_page(a); /* Page_Invalidate_T */ |
85 | if (a == end) |
86 | break; |
87 | a += tc_pagesize; |
88 | } |
89 | } |
90 | |
91 | static void blast_rm7k_tcache(void) |
92 | { |
93 | unsigned long start = CKSEG0ADDR(0); |
94 | unsigned long end = start + tcache_size; |
95 | |
96 | write_c0_taglo(0); |
97 | |
98 | while (start < end) { |
99 | cache_op(Page_Invalidate_T, start); |
100 | start += tc_pagesize; |
101 | } |
102 | } |
103 | |
104 | /* |
105 | * This function is executed in uncached address space. |
106 | */ |
107 | static void __rm7k_tc_enable(void) |
108 | { |
109 | int i; |
110 | |
111 | set_c0_config(RM7K_CONF_TE); |
112 | |
113 | write_c0_taglo(0); |
114 | write_c0_taghi(0); |
115 | |
116 | for (i = 0; i < tcache_size; i += tc_lsize) |
117 | cache_op(Index_Store_Tag_T, CKSEG0ADDR(i)); |
118 | } |
119 | |
120 | static void rm7k_tc_enable(void) |
121 | { |
122 | if (read_c0_config() & RM7K_CONF_TE) |
123 | return; |
124 | |
125 | BUG_ON(tcache_size == 0); |
126 | |
127 | run_uncached(__rm7k_tc_enable); |
128 | } |
129 | |
130 | /* |
131 | * This function is executed in uncached address space. |
132 | */ |
133 | static void __rm7k_sc_enable(void) |
134 | { |
135 | int i; |
136 | |
137 | set_c0_config(RM7K_CONF_SE); |
138 | |
139 | write_c0_taglo(0); |
140 | write_c0_taghi(0); |
141 | |
142 | for (i = 0; i < scache_size; i += sc_lsize) |
143 | cache_op(Index_Store_Tag_SD, CKSEG0ADDR(i)); |
144 | } |
145 | |
146 | static void rm7k_sc_enable(void) |
147 | { |
148 | if (read_c0_config() & RM7K_CONF_SE) |
149 | return; |
150 | |
151 | pr_info("Enabling secondary cache...\n"); |
152 | run_uncached(__rm7k_sc_enable); |
153 | |
154 | if (rm7k_tcache_init) |
155 | rm7k_tc_enable(); |
156 | } |
157 | |
158 | static void rm7k_tc_disable(void) |
159 | { |
160 | unsigned long flags; |
161 | |
162 | local_irq_save(flags); |
163 | blast_rm7k_tcache(); |
164 | clear_c0_config(RM7K_CONF_TE); |
165 | local_irq_save(flags); |
166 | } |
167 | |
168 | static void rm7k_sc_disable(void) |
169 | { |
170 | clear_c0_config(RM7K_CONF_SE); |
171 | |
172 | if (rm7k_tcache_init) |
173 | rm7k_tc_disable(); |
174 | } |
175 | |
176 | static struct bcache_ops rm7k_sc_ops = { |
177 | .bc_enable = rm7k_sc_enable, |
178 | .bc_disable = rm7k_sc_disable, |
179 | .bc_wback_inv = rm7k_sc_wback_inv, |
180 | .bc_inv = rm7k_sc_inv |
181 | }; |
182 | |
183 | /* |
184 | * This is a probing function like the one found in c-r4k.c, we look for the |
185 | * wrap around point with different addresses. |
186 | */ |
187 | static void __probe_tcache(void) |
188 | { |
189 | unsigned long flags, addr, begin, end, pow2; |
190 | |
191 | begin = (unsigned long) &_stext; |
192 | begin &= ~((8 * 1024 * 1024) - 1); |
193 | end = begin + (8 * 1024 * 1024); |
194 | |
195 | local_irq_save(flags); |
196 | |
197 | set_c0_config(RM7K_CONF_TE); |
198 | |
199 | /* Fill size-multiple lines with a valid tag */ |
200 | pow2 = (256 * 1024); |
201 | for (addr = begin; addr <= end; addr = (begin + pow2)) { |
202 | unsigned long *p = (unsigned long *) addr; |
203 | __asm__ __volatile__("nop" : : "r" (*p)); |
204 | pow2 <<= 1; |
205 | } |
206 | |
207 | /* Load first line with a 0 tag, to check after */ |
208 | write_c0_taglo(0); |
209 | write_c0_taghi(0); |
210 | cache_op(Index_Store_Tag_T, begin); |
211 | |
212 | /* Look for the wrap-around */ |
213 | pow2 = (512 * 1024); |
214 | for (addr = begin + (512 * 1024); addr <= end; addr = begin + pow2) { |
215 | cache_op(Index_Load_Tag_T, addr); |
216 | if (!read_c0_taglo()) |
217 | break; |
218 | pow2 <<= 1; |
219 | } |
220 | |
221 | addr -= begin; |
222 | tcache_size = addr; |
223 | |
224 | clear_c0_config(RM7K_CONF_TE); |
225 | |
226 | local_irq_restore(flags); |
227 | } |
228 | |
229 | void rm7k_sc_init(void) |
230 | { |
231 | struct cpuinfo_mips *c = ¤t_cpu_data; |
232 | unsigned int config = read_c0_config(); |
233 | |
234 | if ((config & RM7K_CONF_SC)) |
235 | return; |
236 | |
237 | c->scache.linesz = sc_lsize; |
238 | c->scache.ways = 4; |
239 | c->scache.waybit= __ffs(scache_size / c->scache.ways); |
240 | c->scache.waysize = scache_size / c->scache.ways; |
241 | c->scache.sets = scache_size / (c->scache.linesz * c->scache.ways); |
242 | printk(KERN_INFO "Secondary cache size %dK, linesize %d bytes.\n", |
243 | (scache_size >> 10), sc_lsize); |
244 | |
245 | if (!(config & RM7K_CONF_SE)) |
246 | rm7k_sc_enable(); |
247 | |
248 | bcops = &rm7k_sc_ops; |
249 | |
250 | /* |
251 | * While we're at it let's deal with the tertiary cache. |
252 | */ |
253 | |
254 | rm7k_tcache_init = 0; |
255 | tcache_size = 0; |
256 | |
257 | if (config & RM7K_CONF_TC) |
258 | return; |
259 | |
260 | /* |
261 | * No efficient way to ask the hardware for the size of the tcache, |
262 | * so must probe for it. |
263 | */ |
264 | run_uncached(__probe_tcache); |
265 | rm7k_tc_enable(); |
266 | rm7k_tcache_init = 1; |
267 | c->tcache.linesz = tc_lsize; |
268 | c->tcache.ways = 1; |
269 | pr_info("Tertiary cache size %ldK.\n", (tcache_size >> 10)); |
270 | } |
271 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9