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