• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/mips/cavium-octeon/executive/
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
34const char *octeon_model_get_string(uint32_t chip_id)
35{
36	static char buffer[32];
37	return octeon_model_get_string_buffer(chip_id, buffer);
38}
39
40/*
41 * Version of octeon_model_get_string() that takes buffer as argument,
42 * as running early in u-boot static/global variables don't work when
43 * running from flash.
44 */
45const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
46{
47	const char *family;
48	const char *core_model;
49	char pass[4];
50	int clock_mhz;
51	const char *suffix;
52	union cvmx_l2d_fus3 fus3;
53	int num_cores;
54	union cvmx_mio_fus_dat2 fus_dat2;
55	union cvmx_mio_fus_dat3 fus_dat3;
56	char fuse_model[10];
57	uint32_t fuse_data = 0;
58
59	fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
60	fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
61	fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
62
63	num_cores = cvmx_octeon_num_cores();
64
65	/* Make sure the non existant devices look disabled */
66	switch ((chip_id >> 8) & 0xff) {
67	case 6:		/* CN50XX */
68	case 2:		/* CN30XX */
69		fus_dat3.s.nodfa_dte = 1;
70		fus_dat3.s.nozip = 1;
71		break;
72	case 4:		/* CN57XX or CN56XX */
73		fus_dat3.s.nodfa_dte = 1;
74		break;
75	default:
76		break;
77	}
78
79	/* Make a guess at the suffix */
80	/* NSP = everything */
81	/* EXP = No crypto */
82	/* SCP = No DFA, No zip */
83	/* CP = No DFA, No crypto, No zip */
84	if (fus_dat3.s.nodfa_dte) {
85		if (fus_dat2.s.nocrypto)
86			suffix = "CP";
87		else
88			suffix = "SCP";
89	} else if (fus_dat2.s.nocrypto)
90		suffix = "EXP";
91	else
92		suffix = "NSP";
93
94	/*
95	 * Assume pass number is encoded using <5:3><2:0>. Exceptions
96	 * will be fixed later.
97	 */
98	sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7);
99
100	/*
101	 * Use the number of cores to determine the last 2 digits of
102	 * the model number. There are some exceptions that are fixed
103	 * later.
104	 */
105	switch (num_cores) {
106	case 16:
107		core_model = "60";
108		break;
109	case 15:
110		core_model = "58";
111		break;
112	case 14:
113		core_model = "55";
114		break;
115	case 13:
116		core_model = "52";
117		break;
118	case 12:
119		core_model = "50";
120		break;
121	case 11:
122		core_model = "48";
123		break;
124	case 10:
125		core_model = "45";
126		break;
127	case 9:
128		core_model = "42";
129		break;
130	case 8:
131		core_model = "40";
132		break;
133	case 7:
134		core_model = "38";
135		break;
136	case 6:
137		core_model = "34";
138		break;
139	case 5:
140		core_model = "32";
141		break;
142	case 4:
143		core_model = "30";
144		break;
145	case 3:
146		core_model = "25";
147		break;
148	case 2:
149		core_model = "20";
150		break;
151	case 1:
152		core_model = "10";
153		break;
154	default:
155		core_model = "XX";
156		break;
157	}
158
159	/* Now figure out the family, the first two digits */
160	switch ((chip_id >> 8) & 0xff) {
161	case 0:		/* CN38XX, CN37XX or CN36XX */
162		if (fus3.cn38xx.crip_512k) {
163			/*
164			 * For some unknown reason, the 16 core one is
165			 * called 37 instead of 36.
166			 */
167			if (num_cores >= 16)
168				family = "37";
169			else
170				family = "36";
171		} else
172			family = "38";
173		/*
174		 * This series of chips didn't follow the standard
175		 * pass numbering.
176		 */
177		switch (chip_id & 0xf) {
178		case 0:
179			strcpy(pass, "1.X");
180			break;
181		case 1:
182			strcpy(pass, "2.X");
183			break;
184		case 3:
185			strcpy(pass, "3.X");
186			break;
187		default:
188			strcpy(pass, "X.X");
189			break;
190		}
191		break;
192	case 1:		/* CN31XX or CN3020 */
193		if ((chip_id & 0x10) || fus3.cn31xx.crip_128k)
194			family = "30";
195		else
196			family = "31";
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.0");
204			break;
205		case 2:
206			strcpy(pass, "1.1");
207			break;
208		default:
209			strcpy(pass, "X.X");
210			break;
211		}
212		break;
213	case 2:		/* CN3010 or CN3005 */
214		family = "30";
215		/* A chip with half cache is an 05 */
216		if (fus3.cn30xx.crip_64k)
217			core_model = "05";
218		/*
219		 * This series of chips didn't follow the standard
220		 * pass numbering.
221		 */
222		switch (chip_id & 0xf) {
223		case 0:
224			strcpy(pass, "1.0");
225			break;
226		case 2:
227			strcpy(pass, "1.1");
228			break;
229		default:
230			strcpy(pass, "X.X");
231			break;
232		}
233		break;
234	case 3:		/* CN58XX */
235		family = "58";
236		/* Special case. 4 core, no crypto */
237		if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto)
238			core_model = "29";
239
240		/* Pass 1 uses different encodings for pass numbers */
241		if ((chip_id & 0xFF) < 0x8) {
242			switch (chip_id & 0x3) {
243			case 0:
244				strcpy(pass, "1.0");
245				break;
246			case 1:
247				strcpy(pass, "1.1");
248				break;
249			case 3:
250				strcpy(pass, "1.2");
251				break;
252			default:
253				strcpy(pass, "1.X");
254				break;
255			}
256		}
257		break;
258	case 4:		/* CN57XX, CN56XX, CN55XX, CN54XX */
259		if (fus_dat2.cn56xx.raid_en) {
260			if (fus3.cn56xx.crip_1024k)
261				family = "55";
262			else
263				family = "57";
264			if (fus_dat2.cn56xx.nocrypto)
265				suffix = "SP";
266			else
267				suffix = "SSP";
268		} else {
269			if (fus_dat2.cn56xx.nocrypto)
270				suffix = "CP";
271			else {
272				suffix = "NSP";
273				if (fus_dat3.s.nozip)
274					suffix = "SCP";
275			}
276			if (fus3.cn56xx.crip_1024k)
277				family = "54";
278			else
279				family = "56";
280		}
281		break;
282	case 6:		/* CN50XX */
283		family = "50";
284		break;
285	case 7:		/* CN52XX */
286		if (fus3.cn52xx.crip_256k)
287			family = "51";
288		else
289			family = "52";
290		break;
291	default:
292		family = "XX";
293		core_model = "XX";
294		strcpy(pass, "X.X");
295		suffix = "XXX";
296		break;
297	}
298
299	clock_mhz = octeon_get_clock_rate() / 1000000;
300
301	if (family[0] != '3') {
302		/* Check for model in fuses, overrides normal decode */
303		/* This is _not_ valid for Octeon CN3XXX models */
304		fuse_data |= cvmx_fuse_read_byte(51);
305		fuse_data = fuse_data << 8;
306		fuse_data |= cvmx_fuse_read_byte(50);
307		fuse_data = fuse_data << 8;
308		fuse_data |= cvmx_fuse_read_byte(49);
309		fuse_data = fuse_data << 8;
310		fuse_data |= cvmx_fuse_read_byte(48);
311		if (fuse_data & 0x7ffff) {
312			int model = fuse_data & 0x3fff;
313			int suffix = (fuse_data >> 14) & 0x1f;
314			if (suffix && model) {
315				/*
316				 * Have both number and suffix in
317				 * fuses, so both
318				 */
319				sprintf(fuse_model, "%d%c",
320					model, 'A' + suffix - 1);
321				core_model = "";
322				family = fuse_model;
323			} else if (suffix && !model) {
324				/*
325				 * Only have suffix, so add suffix to
326				 * 'normal' model number.
327				 */
328				sprintf(fuse_model, "%s%c", core_model,
329					'A' + suffix - 1);
330				core_model = fuse_model;
331			} else {
332				/*
333				 * Don't have suffix, so just use
334				 * model from fuses.
335				 */
336				sprintf(fuse_model, "%d", model);
337				core_model = "";
338				family = fuse_model;
339			}
340		}
341	}
342	sprintf(buffer, "CN%s%sp%s-%d-%s",
343		family, core_model, pass, clock_mhz, suffix);
344	return buffer;
345}
346