5105d0d5715402d638dd96a4fdf1133f11213214
[deliverable/linux.git] / arch / mips / cavium-octeon / executive / octeon-model.c
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-2010 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 #include <asm/octeon/octeon.h>
29
30 /**
31 * Read a byte of fuse data
32 * @byte_addr: address to read
33 *
34 * Returns fuse value: 0 or 1
35 */
36 uint8_t cvmx_fuse_read_byte(int byte_addr)
37 {
38 union cvmx_mio_fus_rcmd read_cmd;
39
40 read_cmd.u64 = 0;
41 read_cmd.s.addr = byte_addr;
42 read_cmd.s.pend = 1;
43 cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64);
44 while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD))
45 && read_cmd.s.pend)
46 ;
47 return read_cmd.s.dat;
48 }
49
50 /*
51 * Version of octeon_model_get_string() that takes buffer as argument,
52 * as running early in u-boot static/global variables don't work when
53 * running from flash.
54 */
55 const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
56 {
57 const char *family;
58 const char *core_model;
59 char pass[4];
60 int clock_mhz;
61 const char *suffix;
62 union cvmx_l2d_fus3 fus3;
63 int num_cores;
64 union cvmx_mio_fus_dat2 fus_dat2;
65 union cvmx_mio_fus_dat3 fus_dat3;
66 char fuse_model[10];
67 uint32_t fuse_data = 0;
68
69 fus3.u64 = 0;
70 if (!OCTEON_IS_MODEL(OCTEON_CN6XXX))
71 fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
72 fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
73 fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
74 num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE));
75
76 /* Make sure the non existent devices look disabled */
77 switch ((chip_id >> 8) & 0xff) {
78 case 6: /* CN50XX */
79 case 2: /* CN30XX */
80 fus_dat3.s.nodfa_dte = 1;
81 fus_dat3.s.nozip = 1;
82 break;
83 case 4: /* CN57XX or CN56XX */
84 fus_dat3.s.nodfa_dte = 1;
85 break;
86 default:
87 break;
88 }
89
90 /* Make a guess at the suffix */
91 /* NSP = everything */
92 /* EXP = No crypto */
93 /* SCP = No DFA, No zip */
94 /* CP = No DFA, No crypto, No zip */
95 if (fus_dat3.s.nodfa_dte) {
96 if (fus_dat2.s.nocrypto)
97 suffix = "CP";
98 else
99 suffix = "SCP";
100 } else if (fus_dat2.s.nocrypto)
101 suffix = "EXP";
102 else
103 suffix = "NSP";
104
105 /*
106 * Assume pass number is encoded using <5:3><2:0>. Exceptions
107 * will be fixed later.
108 */
109 sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7);
110
111 /*
112 * Use the number of cores to determine the last 2 digits of
113 * the model number. There are some exceptions that are fixed
114 * later.
115 */
116 switch (num_cores) {
117 case 32:
118 core_model = "80";
119 break;
120 case 24:
121 core_model = "70";
122 break;
123 case 16:
124 core_model = "60";
125 break;
126 case 15:
127 core_model = "58";
128 break;
129 case 14:
130 core_model = "55";
131 break;
132 case 13:
133 core_model = "52";
134 break;
135 case 12:
136 core_model = "50";
137 break;
138 case 11:
139 core_model = "48";
140 break;
141 case 10:
142 core_model = "45";
143 break;
144 case 9:
145 core_model = "42";
146 break;
147 case 8:
148 core_model = "40";
149 break;
150 case 7:
151 core_model = "38";
152 break;
153 case 6:
154 core_model = "34";
155 break;
156 case 5:
157 core_model = "32";
158 break;
159 case 4:
160 core_model = "30";
161 break;
162 case 3:
163 core_model = "25";
164 break;
165 case 2:
166 core_model = "20";
167 break;
168 case 1:
169 core_model = "10";
170 break;
171 default:
172 core_model = "XX";
173 break;
174 }
175
176 /* Now figure out the family, the first two digits */
177 switch ((chip_id >> 8) & 0xff) {
178 case 0: /* CN38XX, CN37XX or CN36XX */
179 if (fus3.cn38xx.crip_512k) {
180 /*
181 * For some unknown reason, the 16 core one is
182 * called 37 instead of 36.
183 */
184 if (num_cores >= 16)
185 family = "37";
186 else
187 family = "36";
188 } else
189 family = "38";
190 /*
191 * This series of chips didn't follow the standard
192 * pass numbering.
193 */
194 switch (chip_id & 0xf) {
195 case 0:
196 strcpy(pass, "1.X");
197 break;
198 case 1:
199 strcpy(pass, "2.X");
200 break;
201 case 3:
202 strcpy(pass, "3.X");
203 break;
204 default:
205 strcpy(pass, "X.X");
206 break;
207 }
208 break;
209 case 1: /* CN31XX or CN3020 */
210 if ((chip_id & 0x10) || fus3.cn31xx.crip_128k)
211 family = "30";
212 else
213 family = "31";
214 /*
215 * This series of chips didn't follow the standard
216 * pass numbering.
217 */
218 switch (chip_id & 0xf) {
219 case 0:
220 strcpy(pass, "1.0");
221 break;
222 case 2:
223 strcpy(pass, "1.1");
224 break;
225 default:
226 strcpy(pass, "X.X");
227 break;
228 }
229 break;
230 case 2: /* CN3010 or CN3005 */
231 family = "30";
232 /* A chip with half cache is an 05 */
233 if (fus3.cn30xx.crip_64k)
234 core_model = "05";
235 /*
236 * This series of chips didn't follow the standard
237 * pass numbering.
238 */
239 switch (chip_id & 0xf) {
240 case 0:
241 strcpy(pass, "1.0");
242 break;
243 case 2:
244 strcpy(pass, "1.1");
245 break;
246 default:
247 strcpy(pass, "X.X");
248 break;
249 }
250 break;
251 case 3: /* CN58XX */
252 family = "58";
253 /* Special case. 4 core, half cache (CP with half cache) */
254 if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2))
255 core_model = "29";
256
257 /* Pass 1 uses different encodings for pass numbers */
258 if ((chip_id & 0xFF) < 0x8) {
259 switch (chip_id & 0x3) {
260 case 0:
261 strcpy(pass, "1.0");
262 break;
263 case 1:
264 strcpy(pass, "1.1");
265 break;
266 case 3:
267 strcpy(pass, "1.2");
268 break;
269 default:
270 strcpy(pass, "1.X");
271 break;
272 }
273 }
274 break;
275 case 4: /* CN57XX, CN56XX, CN55XX, CN54XX */
276 if (fus_dat2.cn56xx.raid_en) {
277 if (fus3.cn56xx.crip_1024k)
278 family = "55";
279 else
280 family = "57";
281 if (fus_dat2.cn56xx.nocrypto)
282 suffix = "SP";
283 else
284 suffix = "SSP";
285 } else {
286 if (fus_dat2.cn56xx.nocrypto)
287 suffix = "CP";
288 else {
289 suffix = "NSP";
290 if (fus_dat3.s.nozip)
291 suffix = "SCP";
292
293 if (fus_dat3.s.bar2_en)
294 suffix = "NSPB2";
295 }
296 if (fus3.cn56xx.crip_1024k)
297 family = "54";
298 else
299 family = "56";
300 }
301 break;
302 case 6: /* CN50XX */
303 family = "50";
304 break;
305 case 7: /* CN52XX */
306 if (fus3.cn52xx.crip_256k)
307 family = "51";
308 else
309 family = "52";
310 break;
311 case 0x93: /* CN61XX */
312 family = "61";
313 if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto)
314 suffix = "AP";
315 if (fus_dat2.cn61xx.nocrypto)
316 suffix = "CP";
317 else if (fus_dat2.cn61xx.dorm_crypto)
318 suffix = "DAP";
319 else if (fus_dat3.cn61xx.nozip)
320 suffix = "SCP";
321 break;
322 case 0x90: /* CN63XX */
323 family = "63";
324 if (fus_dat3.s.l2c_crip == 2)
325 family = "62";
326 if (num_cores == 6) /* Other core counts match generic */
327 core_model = "35";
328 if (fus_dat2.cn63xx.nocrypto)
329 suffix = "CP";
330 else if (fus_dat2.cn63xx.dorm_crypto)
331 suffix = "DAP";
332 else if (fus_dat3.cn63xx.nozip)
333 suffix = "SCP";
334 else
335 suffix = "AAP";
336 break;
337 case 0x92: /* CN66XX */
338 family = "66";
339 if (num_cores == 6) /* Other core counts match generic */
340 core_model = "35";
341 if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto)
342 suffix = "AP";
343 if (fus_dat2.cn66xx.nocrypto)
344 suffix = "CP";
345 else if (fus_dat2.cn66xx.dorm_crypto)
346 suffix = "DAP";
347 else if (fus_dat3.cn66xx.nozip)
348 suffix = "SCP";
349 else
350 suffix = "AAP";
351 break;
352 case 0x91: /* CN68XX */
353 family = "68";
354 if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip)
355 suffix = "CP";
356 else if (fus_dat2.cn68xx.dorm_crypto)
357 suffix = "DAP";
358 else if (fus_dat3.cn68xx.nozip)
359 suffix = "SCP";
360 else if (fus_dat2.cn68xx.nocrypto)
361 suffix = "SP";
362 else
363 suffix = "AAP";
364 break;
365 default:
366 family = "XX";
367 core_model = "XX";
368 strcpy(pass, "X.X");
369 suffix = "XXX";
370 break;
371 }
372
373 clock_mhz = octeon_get_clock_rate() / 1000000;
374 if (family[0] != '3') {
375 int fuse_base = 384 / 8;
376 if (family[0] == '6')
377 fuse_base = 832 / 8;
378
379 /* Check for model in fuses, overrides normal decode */
380 /* This is _not_ valid for Octeon CN3XXX models */
381 fuse_data |= cvmx_fuse_read_byte(fuse_base + 3);
382 fuse_data = fuse_data << 8;
383 fuse_data |= cvmx_fuse_read_byte(fuse_base + 2);
384 fuse_data = fuse_data << 8;
385 fuse_data |= cvmx_fuse_read_byte(fuse_base + 1);
386 fuse_data = fuse_data << 8;
387 fuse_data |= cvmx_fuse_read_byte(fuse_base);
388 if (fuse_data & 0x7ffff) {
389 int model = fuse_data & 0x3fff;
390 int suffix = (fuse_data >> 14) & 0x1f;
391 if (suffix && model) {
392 /* Have both number and suffix in fuses, so both */
393 sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1);
394 core_model = "";
395 family = fuse_model;
396 } else if (suffix && !model) {
397 /* Only have suffix, so add suffix to 'normal' model number */
398 sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1);
399 core_model = fuse_model;
400 } else {
401 /* Don't have suffix, so just use model from fuses */
402 sprintf(fuse_model, "%d", model);
403 core_model = "";
404 family = fuse_model;
405 }
406 }
407 }
408 sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix);
409 return buffer;
410 }
411
412 /**
413 * Given the chip processor ID from COP0, this function returns a
414 * string representing the chip model number. The string is of the
415 * form CNXXXXpX.X-FREQ-SUFFIX.
416 * - XXXX = The chip model number
417 * - X.X = Chip pass number
418 * - FREQ = Current frequency in Mhz
419 * - SUFFIX = NSP, EXP, SCP, SSP, or CP
420 *
421 * @chip_id: Chip ID
422 *
423 * Returns Model string
424 */
425 const char *octeon_model_get_string(uint32_t chip_id)
426 {
427 static char buffer[32];
428 return octeon_model_get_string_buffer(chip_id, buffer);
429 }
This page took 0.04466 seconds and 4 git commands to generate.