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 }
410