Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/cavium-octeon/executive/octeon-model.c
10818 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-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 existent 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
}
359
360