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