Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[cascardo/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  * Given the chip processor ID from COP0, this function returns a
32  * string representing the chip model number. The string is of the
33  * form CNXXXXpX.X-FREQ-SUFFIX.
34  * - XXXX = The chip model number
35  * - X.X = Chip pass number
36  * - FREQ = Current frequency in Mhz
37  * - SUFFIX = NSP, EXP, SCP, SSP, or CP
38  *
39  * @chip_id: Chip ID
40  *
41  * Returns Model string
42  */
43 const char *octeon_model_get_string(uint32_t chip_id)
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  */
54 const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
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;
69         if (!OCTEON_IS_MODEL(OCTEON_CN6XXX))
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 }