diff options
Diffstat (limited to 'arch/mips/cavium-octeon/executive/octeon-model.c')
-rw-r--r-- | arch/mips/cavium-octeon/executive/octeon-model.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c new file mode 100644 index 000000000000..9afc3794ed1b --- /dev/null +++ b/arch/mips/cavium-octeon/executive/octeon-model.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * File defining functions for working with different Octeon | ||
30 | * models. | ||
31 | */ | ||
32 | #include <asm/octeon/octeon.h> | ||
33 | |||
34 | /** | ||
35 | * Given the chip processor ID from COP0, this function returns a | ||
36 | * string representing the chip model number. The string is of the | ||
37 | * form CNXXXXpX.X-FREQ-SUFFIX. | ||
38 | * - XXXX = The chip model number | ||
39 | * - X.X = Chip pass number | ||
40 | * - FREQ = Current frequency in Mhz | ||
41 | * - SUFFIX = NSP, EXP, SCP, SSP, or CP | ||
42 | * | ||
43 | * @chip_id: Chip ID | ||
44 | * | ||
45 | * Returns Model string | ||
46 | */ | ||
47 | const char *octeon_model_get_string(uint32_t chip_id) | ||
48 | { | ||
49 | static char buffer[32]; | ||
50 | return octeon_model_get_string_buffer(chip_id, buffer); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Version of octeon_model_get_string() that takes buffer as argument, | ||
55 | * as running early in u-boot static/global variables don't work when | ||
56 | * running from flash. | ||
57 | */ | ||
58 | const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) | ||
59 | { | ||
60 | const char *family; | ||
61 | const char *core_model; | ||
62 | char pass[4]; | ||
63 | int clock_mhz; | ||
64 | const char *suffix; | ||
65 | union cvmx_l2d_fus3 fus3; | ||
66 | int num_cores; | ||
67 | union cvmx_mio_fus_dat2 fus_dat2; | ||
68 | union cvmx_mio_fus_dat3 fus_dat3; | ||
69 | char fuse_model[10]; | ||
70 | uint32_t fuse_data = 0; | ||
71 | |||
72 | fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); | ||
73 | fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); | ||
74 | fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); | ||
75 | |||
76 | num_cores = cvmx_octeon_num_cores(); | ||
77 | |||
78 | /* Make sure the non existant devices look disabled */ | ||
79 | switch ((chip_id >> 8) & 0xff) { | ||
80 | case 6: /* CN50XX */ | ||
81 | case 2: /* CN30XX */ | ||
82 | fus_dat3.s.nodfa_dte = 1; | ||
83 | fus_dat3.s.nozip = 1; | ||
84 | break; | ||
85 | case 4: /* CN57XX or CN56XX */ | ||
86 | fus_dat3.s.nodfa_dte = 1; | ||
87 | break; | ||
88 | default: | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | /* Make a guess at the suffix */ | ||
93 | /* NSP = everything */ | ||
94 | /* EXP = No crypto */ | ||
95 | /* SCP = No DFA, No zip */ | ||
96 | /* CP = No DFA, No crypto, No zip */ | ||
97 | if (fus_dat3.s.nodfa_dte) { | ||
98 | if (fus_dat2.s.nocrypto) | ||
99 | suffix = "CP"; | ||
100 | else | ||
101 | suffix = "SCP"; | ||
102 | } else if (fus_dat2.s.nocrypto) | ||
103 | suffix = "EXP"; | ||
104 | else | ||
105 | suffix = "NSP"; | ||
106 | |||
107 | /* | ||
108 | * Assume pass number is encoded using <5:3><2:0>. Exceptions | ||
109 | * will be fixed later. | ||
110 | */ | ||
111 | sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7); | ||
112 | |||
113 | /* | ||
114 | * Use the number of cores to determine the last 2 digits of | ||
115 | * the model number. There are some exceptions that are fixed | ||
116 | * later. | ||
117 | */ | ||
118 | switch (num_cores) { | ||
119 | case 16: | ||
120 | core_model = "60"; | ||
121 | break; | ||
122 | case 15: | ||
123 | core_model = "58"; | ||
124 | break; | ||
125 | case 14: | ||
126 | core_model = "55"; | ||
127 | break; | ||
128 | case 13: | ||
129 | core_model = "52"; | ||
130 | break; | ||
131 | case 12: | ||
132 | core_model = "50"; | ||
133 | break; | ||
134 | case 11: | ||
135 | core_model = "48"; | ||
136 | break; | ||
137 | case 10: | ||
138 | core_model = "45"; | ||
139 | break; | ||
140 | case 9: | ||
141 | core_model = "42"; | ||
142 | break; | ||
143 | case 8: | ||
144 | core_model = "40"; | ||
145 | break; | ||
146 | case 7: | ||
147 | core_model = "38"; | ||
148 | break; | ||
149 | case 6: | ||
150 | core_model = "34"; | ||
151 | break; | ||
152 | case 5: | ||
153 | core_model = "32"; | ||
154 | break; | ||
155 | case 4: | ||
156 | core_model = "30"; | ||
157 | break; | ||
158 | case 3: | ||
159 | core_model = "25"; | ||
160 | break; | ||
161 | case 2: | ||
162 | core_model = "20"; | ||
163 | break; | ||
164 | case 1: | ||
165 | core_model = "10"; | ||
166 | break; | ||
167 | default: | ||
168 | core_model = "XX"; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | /* Now figure out the family, the first two digits */ | ||
173 | switch ((chip_id >> 8) & 0xff) { | ||
174 | case 0: /* CN38XX, CN37XX or CN36XX */ | ||
175 | if (fus3.cn38xx.crip_512k) { | ||
176 | /* | ||
177 | * For some unknown reason, the 16 core one is | ||
178 | * called 37 instead of 36. | ||
179 | */ | ||
180 | if (num_cores >= 16) | ||
181 | family = "37"; | ||
182 | else | ||
183 | family = "36"; | ||
184 | } else | ||
185 | family = "38"; | ||
186 | /* | ||
187 | * This series of chips didn't follow the standard | ||
188 | * pass numbering. | ||
189 | */ | ||
190 | switch (chip_id & 0xf) { | ||
191 | case 0: | ||
192 | strcpy(pass, "1.X"); | ||
193 | break; | ||
194 | case 1: | ||
195 | strcpy(pass, "2.X"); | ||
196 | break; | ||
197 | case 3: | ||
198 | strcpy(pass, "3.X"); | ||
199 | break; | ||
200 | default: | ||
201 | strcpy(pass, "X.X"); | ||
202 | break; | ||
203 | } | ||
204 | break; | ||
205 | case 1: /* CN31XX or CN3020 */ | ||
206 | if ((chip_id & 0x10) || fus3.cn31xx.crip_128k) | ||
207 | family = "30"; | ||
208 | else | ||
209 | family = "31"; | ||
210 | /* | ||
211 | * This series of chips didn't follow the standard | ||
212 | * pass numbering. | ||
213 | */ | ||
214 | switch (chip_id & 0xf) { | ||
215 | case 0: | ||
216 | strcpy(pass, "1.0"); | ||
217 | break; | ||
218 | case 2: | ||
219 | strcpy(pass, "1.1"); | ||
220 | break; | ||
221 | default: | ||
222 | strcpy(pass, "X.X"); | ||
223 | break; | ||
224 | } | ||
225 | break; | ||
226 | case 2: /* CN3010 or CN3005 */ | ||
227 | family = "30"; | ||
228 | /* A chip with half cache is an 05 */ | ||
229 | if (fus3.cn30xx.crip_64k) | ||
230 | core_model = "05"; | ||
231 | /* | ||
232 | * This series of chips didn't follow the standard | ||
233 | * pass numbering. | ||
234 | */ | ||
235 | switch (chip_id & 0xf) { | ||
236 | case 0: | ||
237 | strcpy(pass, "1.0"); | ||
238 | break; | ||
239 | case 2: | ||
240 | strcpy(pass, "1.1"); | ||
241 | break; | ||
242 | default: | ||
243 | strcpy(pass, "X.X"); | ||
244 | break; | ||
245 | } | ||
246 | break; | ||
247 | case 3: /* CN58XX */ | ||
248 | family = "58"; | ||
249 | /* Special case. 4 core, no crypto */ | ||
250 | if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto) | ||
251 | core_model = "29"; | ||
252 | |||
253 | /* Pass 1 uses different encodings for pass numbers */ | ||
254 | if ((chip_id & 0xFF) < 0x8) { | ||
255 | switch (chip_id & 0x3) { | ||
256 | case 0: | ||
257 | strcpy(pass, "1.0"); | ||
258 | break; | ||
259 | case 1: | ||
260 | strcpy(pass, "1.1"); | ||
261 | break; | ||
262 | case 3: | ||
263 | strcpy(pass, "1.2"); | ||
264 | break; | ||
265 | default: | ||
266 | strcpy(pass, "1.X"); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | break; | ||
271 | case 4: /* CN57XX, CN56XX, CN55XX, CN54XX */ | ||
272 | if (fus_dat2.cn56xx.raid_en) { | ||
273 | if (fus3.cn56xx.crip_1024k) | ||
274 | family = "55"; | ||
275 | else | ||
276 | family = "57"; | ||
277 | if (fus_dat2.cn56xx.nocrypto) | ||
278 | suffix = "SP"; | ||
279 | else | ||
280 | suffix = "SSP"; | ||
281 | } else { | ||
282 | if (fus_dat2.cn56xx.nocrypto) | ||
283 | suffix = "CP"; | ||
284 | else { | ||
285 | suffix = "NSP"; | ||
286 | if (fus_dat3.s.nozip) | ||
287 | suffix = "SCP"; | ||
288 | } | ||
289 | if (fus3.cn56xx.crip_1024k) | ||
290 | family = "54"; | ||
291 | else | ||
292 | family = "56"; | ||
293 | } | ||
294 | break; | ||
295 | case 6: /* CN50XX */ | ||
296 | family = "50"; | ||
297 | break; | ||
298 | case 7: /* CN52XX */ | ||
299 | if (fus3.cn52xx.crip_256k) | ||
300 | family = "51"; | ||
301 | else | ||
302 | family = "52"; | ||
303 | break; | ||
304 | default: | ||
305 | family = "XX"; | ||
306 | core_model = "XX"; | ||
307 | strcpy(pass, "X.X"); | ||
308 | suffix = "XXX"; | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | clock_mhz = octeon_get_clock_rate() / 1000000; | ||
313 | |||
314 | if (family[0] != '3') { | ||
315 | /* Check for model in fuses, overrides normal decode */ | ||
316 | /* This is _not_ valid for Octeon CN3XXX models */ | ||
317 | fuse_data |= cvmx_fuse_read_byte(51); | ||
318 | fuse_data = fuse_data << 8; | ||
319 | fuse_data |= cvmx_fuse_read_byte(50); | ||
320 | fuse_data = fuse_data << 8; | ||
321 | fuse_data |= cvmx_fuse_read_byte(49); | ||
322 | fuse_data = fuse_data << 8; | ||
323 | fuse_data |= cvmx_fuse_read_byte(48); | ||
324 | if (fuse_data & 0x7ffff) { | ||
325 | int model = fuse_data & 0x3fff; | ||
326 | int suffix = (fuse_data >> 14) & 0x1f; | ||
327 | if (suffix && model) { | ||
328 | /* | ||
329 | * Have both number and suffix in | ||
330 | * fuses, so both | ||
331 | */ | ||
332 | sprintf(fuse_model, "%d%c", | ||
333 | model, 'A' + suffix - 1); | ||
334 | core_model = ""; | ||
335 | family = fuse_model; | ||
336 | } else if (suffix && !model) { | ||
337 | /* | ||
338 | * Only have suffix, so add suffix to | ||
339 | * 'normal' model number. | ||
340 | */ | ||
341 | sprintf(fuse_model, "%s%c", core_model, | ||
342 | 'A' + suffix - 1); | ||
343 | core_model = fuse_model; | ||
344 | } else { | ||
345 | /* | ||
346 | * Don't have suffix, so just use | ||
347 | * model from fuses. | ||
348 | */ | ||
349 | sprintf(fuse_model, "%d", model); | ||
350 | core_model = ""; | ||
351 | family = fuse_model; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | sprintf(buffer, "CN%s%sp%s-%d-%s", | ||
356 | family, core_model, pass, clock_mhz, suffix); | ||
357 | return buffer; | ||
358 | } | ||