Commit | Line | Data |
---|---|---|
9318c51a CD |
1 | /* |
2 | * Copyright (C) 2006 Chris Dearman (chris@mips.com), | |
3 | */ | |
4 | #include <linux/init.h> | |
5 | #include <linux/kernel.h> | |
6 | #include <linux/sched.h> | |
7 | #include <linux/mm.h> | |
8 | ||
69f24d17 | 9 | #include <asm/cpu-type.h> |
9318c51a CD |
10 | #include <asm/mipsregs.h> |
11 | #include <asm/bcache.h> | |
12 | #include <asm/cacheops.h> | |
13 | #include <asm/page.h> | |
14 | #include <asm/pgtable.h> | |
9318c51a CD |
15 | #include <asm/mmu_context.h> |
16 | #include <asm/r4kcache.h> | |
7d53e9c4 | 17 | #include <asm/mips-cm.h> |
9318c51a CD |
18 | |
19 | /* | |
20 | * MIPS32/MIPS64 L2 cache handling | |
21 | */ | |
22 | ||
23 | /* | |
24 | * Writeback and invalidate the secondary cache before DMA. | |
25 | */ | |
26 | static void mips_sc_wback_inv(unsigned long addr, unsigned long size) | |
27 | { | |
a2c2bc4b | 28 | blast_scache_range(addr, addr + size); |
9318c51a CD |
29 | } |
30 | ||
31 | /* | |
32 | * Invalidate the secondary cache before DMA. | |
33 | */ | |
34 | static void mips_sc_inv(unsigned long addr, unsigned long size) | |
35 | { | |
96983ffe KC |
36 | unsigned long lsize = cpu_scache_line_size(); |
37 | unsigned long almask = ~(lsize - 1); | |
38 | ||
39 | cache_op(Hit_Writeback_Inv_SD, addr & almask); | |
40 | cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask); | |
a2c2bc4b | 41 | blast_inv_scache_range(addr, addr + size); |
9318c51a CD |
42 | } |
43 | ||
44 | static void mips_sc_enable(void) | |
45 | { | |
46 | /* L2 cache is permanently enabled */ | |
47 | } | |
48 | ||
49 | static void mips_sc_disable(void) | |
50 | { | |
51 | /* L2 cache is permanently enabled */ | |
52 | } | |
53 | ||
4d035516 PB |
54 | static void mips_sc_prefetch_enable(void) |
55 | { | |
56 | unsigned long pftctl; | |
57 | ||
58 | if (mips_cm_revision() < CM_REV_CM2_5) | |
59 | return; | |
60 | ||
61 | /* | |
62 | * If there is one or more L2 prefetch unit present then enable | |
63 | * prefetching for both code & data, for all ports. | |
64 | */ | |
65 | pftctl = read_gcr_l2_pft_control(); | |
66 | if (pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK) { | |
67 | pftctl &= ~CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK; | |
68 | pftctl |= PAGE_MASK & CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK; | |
69 | pftctl |= CM_GCR_L2_PFT_CONTROL_PFTEN_MSK; | |
70 | write_gcr_l2_pft_control(pftctl); | |
71 | ||
72 | pftctl = read_gcr_l2_pft_control_b(); | |
73 | pftctl |= CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK; | |
74 | pftctl |= CM_GCR_L2_PFT_CONTROL_B_CEN_MSK; | |
75 | write_gcr_l2_pft_control_b(pftctl); | |
76 | } | |
77 | } | |
78 | ||
79 | static void mips_sc_prefetch_disable(void) | |
80 | { | |
81 | unsigned long pftctl; | |
82 | ||
83 | if (mips_cm_revision() < CM_REV_CM2_5) | |
84 | return; | |
85 | ||
86 | pftctl = read_gcr_l2_pft_control(); | |
87 | pftctl &= ~CM_GCR_L2_PFT_CONTROL_PFTEN_MSK; | |
88 | write_gcr_l2_pft_control(pftctl); | |
89 | ||
90 | pftctl = read_gcr_l2_pft_control_b(); | |
91 | pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK; | |
92 | pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_CEN_MSK; | |
93 | write_gcr_l2_pft_control_b(pftctl); | |
94 | } | |
95 | ||
96 | static bool mips_sc_prefetch_is_enabled(void) | |
97 | { | |
98 | unsigned long pftctl; | |
99 | ||
100 | if (mips_cm_revision() < CM_REV_CM2_5) | |
101 | return false; | |
102 | ||
103 | pftctl = read_gcr_l2_pft_control(); | |
104 | if (!(pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK)) | |
105 | return false; | |
106 | return !!(pftctl & CM_GCR_L2_PFT_CONTROL_PFTEN_MSK); | |
107 | } | |
108 | ||
9318c51a CD |
109 | static struct bcache_ops mips_sc_ops = { |
110 | .bc_enable = mips_sc_enable, | |
111 | .bc_disable = mips_sc_disable, | |
112 | .bc_wback_inv = mips_sc_wback_inv, | |
4d035516 PB |
113 | .bc_inv = mips_sc_inv, |
114 | .bc_prefetch_enable = mips_sc_prefetch_enable, | |
115 | .bc_prefetch_disable = mips_sc_prefetch_disable, | |
116 | .bc_prefetch_is_enabled = mips_sc_prefetch_is_enabled, | |
9318c51a CD |
117 | }; |
118 | ||
ea31a6b2 KC |
119 | /* |
120 | * Check if the L2 cache controller is activated on a particular platform. | |
121 | * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS | |
122 | * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the | |
123 | * cache being disabled. However there is no guarantee for this to be | |
124 | * true on all platforms. In an act of stupidity the spec defined bits | |
125 | * 12..15 as implementation defined so below function will eventually have | |
126 | * to be replaced by a platform specific probe. | |
127 | */ | |
128 | static inline int mips_sc_is_activated(struct cpuinfo_mips *c) | |
129 | { | |
081d835f KC |
130 | unsigned int config2 = read_c0_config2(); |
131 | unsigned int tmp; | |
132 | ||
ea31a6b2 | 133 | /* Check the bypass bit (L2B) */ |
69f24d17 | 134 | switch (current_cpu_type()) { |
ea31a6b2 KC |
135 | case CPU_34K: |
136 | case CPU_74K: | |
137 | case CPU_1004K: | |
442e14a2 | 138 | case CPU_1074K: |
26ab96df | 139 | case CPU_INTERAPTIV: |
708ac4b8 | 140 | case CPU_PROAPTIV: |
aced4cbd | 141 | case CPU_P5600: |
ea31a6b2 | 142 | case CPU_BMIPS5000: |
4695089f | 143 | case CPU_QEMU_GENERIC: |
ea31a6b2 KC |
144 | if (config2 & (1 << 12)) |
145 | return 0; | |
146 | } | |
147 | ||
148 | tmp = (config2 >> 4) & 0x0f; | |
149 | if (0 < tmp && tmp <= 7) | |
150 | c->scache.linesz = 2 << tmp; | |
151 | else | |
152 | return 0; | |
081d835f | 153 | return 1; |
ea31a6b2 KC |
154 | } |
155 | ||
7d53e9c4 PB |
156 | static int __init mips_sc_probe_cm3(void) |
157 | { | |
158 | struct cpuinfo_mips *c = ¤t_cpu_data; | |
159 | unsigned long cfg = read_gcr_l2_config(); | |
160 | unsigned long sets, line_sz, assoc; | |
161 | ||
162 | if (cfg & CM_GCR_L2_CONFIG_BYPASS_MSK) | |
163 | return 0; | |
164 | ||
165 | sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK; | |
166 | sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF; | |
56fa81fc GR |
167 | if (sets) |
168 | c->scache.sets = 64 << sets; | |
7d53e9c4 PB |
169 | |
170 | line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK; | |
171 | line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF; | |
56fa81fc GR |
172 | if (line_sz) |
173 | c->scache.linesz = 2 << line_sz; | |
7d53e9c4 PB |
174 | |
175 | assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK; | |
176 | assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF; | |
177 | c->scache.ways = assoc + 1; | |
178 | c->scache.waysize = c->scache.sets * c->scache.linesz; | |
179 | c->scache.waybit = __ffs(c->scache.waysize); | |
180 | ||
56fa81fc GR |
181 | if (c->scache.linesz) { |
182 | c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; | |
183 | return 1; | |
184 | } | |
7d53e9c4 | 185 | |
56fa81fc | 186 | return 0; |
7d53e9c4 PB |
187 | } |
188 | ||
9318c51a CD |
189 | static inline int __init mips_sc_probe(void) |
190 | { | |
191 | struct cpuinfo_mips *c = ¤t_cpu_data; | |
192 | unsigned int config1, config2; | |
193 | unsigned int tmp; | |
194 | ||
195 | /* Mark as not present until probe completed */ | |
196 | c->scache.flags |= MIPS_CACHE_NOT_PRESENT; | |
197 | ||
7d53e9c4 PB |
198 | if (mips_cm_revision() >= CM_REV_CM3) |
199 | return mips_sc_probe_cm3(); | |
200 | ||
9318c51a | 201 | /* Ignore anything but MIPSxx processors */ |
adb37892 | 202 | if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | |
b5ad2c21 MC |
203 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | |
204 | MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6))) | |
9318c51a CD |
205 | return 0; |
206 | ||
207 | /* Does this MIPS32/MIPS64 CPU have a config2 register? */ | |
208 | config1 = read_c0_config1(); | |
209 | if (!(config1 & MIPS_CONF_M)) | |
210 | return 0; | |
211 | ||
212 | config2 = read_c0_config2(); | |
ea31a6b2 KC |
213 | |
214 | if (!mips_sc_is_activated(c)) | |
9318c51a CD |
215 | return 0; |
216 | ||
217 | tmp = (config2 >> 8) & 0x0f; | |
05513992 | 218 | if (tmp <= 7) |
9318c51a CD |
219 | c->scache.sets = 64 << tmp; |
220 | else | |
221 | return 0; | |
222 | ||
223 | tmp = (config2 >> 0) & 0x0f; | |
05513992 | 224 | if (tmp <= 7) |
9318c51a CD |
225 | c->scache.ways = tmp + 1; |
226 | else | |
227 | return 0; | |
228 | ||
229 | c->scache.waysize = c->scache.sets * c->scache.linesz; | |
a2c2bc4b | 230 | c->scache.waybit = __ffs(c->scache.waysize); |
9318c51a CD |
231 | |
232 | c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; | |
233 | ||
234 | return 1; | |
235 | } | |
236 | ||
078a55fc | 237 | int mips_sc_init(void) |
9318c51a | 238 | { |
49a89efb | 239 | int found = mips_sc_probe(); |
9318c51a CD |
240 | if (found) { |
241 | mips_sc_enable(); | |
4d035516 | 242 | mips_sc_prefetch_enable(); |
9318c51a CD |
243 | bcops = &mips_sc_ops; |
244 | } | |
245 | return found; | |
246 | } |