Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx
[linux-2.6] / 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-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 existant 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 }