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