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