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