File Index
Files and directories
Sign in
FILE

octeon-model.c

File preview with syntax highlighting.

linux-6.19.14/arch/mips/cavium-octeon/executive/octeon-model.c 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-2017 Cavium, Inc.
  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 <linux/string.h>
 29#include <asm/octeon/octeon.h>
 30
 31enum octeon_feature_bits __octeon_feature_bits __read_mostly;
 32EXPORT_SYMBOL_GPL(__octeon_feature_bits);
 33
 34/**
 35 * Read a byte of fuse data
 36 * @byte_addr:	 address to read
 37 *
 38 * Returns fuse value: 0 or 1
 39 */
 40static uint8_t __init cvmx_fuse_read_byte(int byte_addr)
 41{
 42	union cvmx_mio_fus_rcmd read_cmd;
 43
 44	read_cmd.u64 = 0;
 45	read_cmd.s.addr = byte_addr;
 46	read_cmd.s.pend = 1;
 47	cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64);
 48	while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD))
 49	       && read_cmd.s.pend)
 50		;
 51	return read_cmd.s.dat;
 52}
 53
 54/*
 55 * Version of octeon_model_get_string() that takes buffer as argument,
 56 * as running early in u-boot static/global variables don't work when
 57 * running from flash.
 58 */
 59static const char *__init octeon_model_get_string_buffer(uint32_t chip_id,
 60							 char *buffer)
 61{
 62	const char *family;
 63	const char *core_model;
 64	char pass[4];
 65	int clock_mhz;
 66	const char *suffix;
 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	uint64_t l2d_fus3 = 0;
 73
 74	if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX))
 75		l2d_fus3 = (cvmx_read_csr(CVMX_L2D_FUS3) >> 34) & 0x3;
 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_octeon_num_cores();
 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 48:
125		core_model = "90";
126		break;
127	case 44:
128		core_model = "88";
129		break;
130	case 40:
131		core_model = "85";
132		break;
133	case 32:
134		core_model = "80";
135		break;
136	case 24:
137		core_model = "70";
138		break;
139	case 16:
140		core_model = "60";
141		break;
142	case 15:
143		core_model = "58";
144		break;
145	case 14:
146		core_model = "55";
147		break;
148	case 13:
149		core_model = "52";
150		break;
151	case 12:
152		core_model = "50";
153		break;
154	case 11:
155		core_model = "48";
156		break;
157	case 10:
158		core_model = "45";
159		break;
160	case 9:
161		core_model = "42";
162		break;
163	case 8:
164		core_model = "40";
165		break;
166	case 7:
167		core_model = "38";
168		break;
169	case 6:
170		core_model = "34";
171		break;
172	case 5:
173		core_model = "32";
174		break;
175	case 4:
176		core_model = "30";
177		break;
178	case 3:
179		core_model = "25";
180		break;
181	case 2:
182		core_model = "20";
183		break;
184	case 1:
185		core_model = "10";
186		break;
187	default:
188		core_model = "XX";
189		break;
190	}
191
192	/* Now figure out the family, the first two digits */
193	switch ((chip_id >> 8) & 0xff) {
194	case 0:		/* CN38XX, CN37XX or CN36XX */
195		if (l2d_fus3) {
196			/*
197			 * For some unknown reason, the 16 core one is
198			 * called 37 instead of 36.
199			 */
200			if (num_cores >= 16)
201				family = "37";
202			else
203				family = "36";
204		} else
205			family = "38";
206		/*
207		 * This series of chips didn't follow the standard
208		 * pass numbering.
209		 */
210		switch (chip_id & 0xf) {
211		case 0:
212			strscpy(pass, "1.X");
213			break;
214		case 1:
215			strscpy(pass, "2.X");
216			break;
217		case 3:
218			strscpy(pass, "3.X");
219			break;
220		default:
221			strscpy(pass, "X.X");
222			break;
223		}
224		break;
225	case 1:		/* CN31XX or CN3020 */
226		if ((chip_id & 0x10) || l2d_fus3)
227			family = "30";
228		else
229			family = "31";
230		/*
231		 * This series of chips didn't follow the standard
232		 * pass numbering.
233		 */
234		switch (chip_id & 0xf) {
235		case 0:
236			strscpy(pass, "1.0");
237			break;
238		case 2:
239			strscpy(pass, "1.1");
240			break;
241		default:
242			strscpy(pass, "X.X");
243			break;
244		}
245		break;
246	case 2:		/* CN3010 or CN3005 */
247		family = "30";
248		/* A chip with half cache is an 05 */
249		if (l2d_fus3)
250			core_model = "05";
251		/*
252		 * This series of chips didn't follow the standard
253		 * pass numbering.
254		 */
255		switch (chip_id & 0xf) {
256		case 0:
257			strscpy(pass, "1.0");
258			break;
259		case 2:
260			strscpy(pass, "1.1");
261			break;
262		default:
263			strscpy(pass, "X.X");
264			break;
265		}
266		break;
267	case 3:		/* CN58XX */
268		family = "58";
269		/* Special case. 4 core, half cache (CP with half cache) */
270		if ((num_cores == 4) && l2d_fus3 && !strncmp(suffix, "CP", 2))
271			core_model = "29";
272
273		/* Pass 1 uses different encodings for pass numbers */
274		if ((chip_id & 0xFF) < 0x8) {
275			switch (chip_id & 0x3) {
276			case 0:
277				strscpy(pass, "1.0");
278				break;
279			case 1:
280				strscpy(pass, "1.1");
281				break;
282			case 3:
283				strscpy(pass, "1.2");
284				break;
285			default:
286				strscpy(pass, "1.X");
287				break;
288			}
289		}
290		break;
291	case 4:		/* CN57XX, CN56XX, CN55XX, CN54XX */
292		if (fus_dat2.cn56xx.raid_en) {
293			if (l2d_fus3)
294				family = "55";
295			else
296				family = "57";
297			if (fus_dat2.cn56xx.nocrypto)
298				suffix = "SP";
299			else
300				suffix = "SSP";
301		} else {
302			if (fus_dat2.cn56xx.nocrypto)
303				suffix = "CP";
304			else {
305				suffix = "NSP";
306				if (fus_dat3.s.nozip)
307					suffix = "SCP";
308
309				if (fus_dat3.cn38xx.bar2_en)
310					suffix = "NSPB2";
311			}
312			if (l2d_fus3)
313				family = "54";
314			else
315				family = "56";
316		}
317		break;
318	case 6:		/* CN50XX */
319		family = "50";
320		break;
321	case 7:		/* CN52XX */
322		if (l2d_fus3)
323			family = "51";
324		else
325			family = "52";
326		break;
327	case 0x93:		/* CN61XX */
328		family = "61";
329		if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto)
330			suffix = "AP";
331		if (fus_dat2.cn61xx.nocrypto)
332			suffix = "CP";
333		else if (fus_dat2.cn61xx.dorm_crypto)
334			suffix = "DAP";
335		else if (fus_dat3.cn61xx.nozip)
336			suffix = "SCP";
337		break;
338	case 0x90:		/* CN63XX */
339		family = "63";
340		if (fus_dat3.s.l2c_crip == 2)
341			family = "62";
342		if (num_cores == 6)	/* Other core counts match generic */
343			core_model = "35";
344		if (fus_dat2.cn63xx.nocrypto)
345			suffix = "CP";
346		else if (fus_dat2.cn63xx.dorm_crypto)
347			suffix = "DAP";
348		else if (fus_dat3.cn61xx.nozip)
349			suffix = "SCP";
350		else
351			suffix = "AAP";
352		break;
353	case 0x92:		/* CN66XX */
354		family = "66";
355		if (num_cores == 6)	/* Other core counts match generic */
356			core_model = "35";
357		if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto)
358			suffix = "AP";
359		if (fus_dat2.cn66xx.nocrypto)
360			suffix = "CP";
361		else if (fus_dat2.cn66xx.dorm_crypto)
362			suffix = "DAP";
363		else if (fus_dat3.cn61xx.nozip)
364			suffix = "SCP";
365		else
366			suffix = "AAP";
367		break;
368	case 0x91:		/* CN68XX */
369		family = "68";
370		if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn61xx.nozip)
371			suffix = "CP";
372		else if (fus_dat2.cn68xx.dorm_crypto)
373			suffix = "DAP";
374		else if (fus_dat3.cn61xx.nozip)
375			suffix = "SCP";
376		else if (fus_dat2.cn68xx.nocrypto)
377			suffix = "SP";
378		else
379			suffix = "AAP";
380		break;
381	case 0x94:		/* CNF71XX */
382		family = "F71";
383		if (fus_dat3.cn61xx.nozip)
384			suffix = "SCP";
385		else
386			suffix = "AAP";
387		break;
388	case 0x95:		/* CN78XX */
389		if (num_cores == 6)	/* Other core counts match generic */
390			core_model = "35";
391		if (OCTEON_IS_MODEL(OCTEON_CN76XX))
392			family = "76";
393		else
394			family = "78";
395		if (fus_dat3.cn78xx.l2c_crip == 2)
396			family = "77";
397		if (fus_dat3.cn78xx.nozip
398		    && fus_dat3.cn78xx.nodfa_dte
399		    && fus_dat3.cn78xx.nohna_dte) {
400			if (fus_dat3.cn78xx.nozip &&
401				!fus_dat2.cn78xx.raid_en &&
402				fus_dat3.cn78xx.nohna_dte) {
403				suffix = "CP";
404			} else {
405				suffix = "SCP";
406			}
407		} else if (fus_dat2.cn78xx.raid_en == 0)
408			suffix = "HCP";
409		else
410			suffix = "AAP";
411		break;
412	case 0x96:		/* CN70XX */
413		family = "70";
414		if (cvmx_read_csr(CVMX_MIO_FUS_PDF) & (0x1ULL << 32))
415			family = "71";
416		if (fus_dat2.cn70xx.nocrypto)
417			suffix = "CP";
418		else if (fus_dat3.cn70xx.nodfa_dte)
419			suffix = "SCP";
420		else
421			suffix = "AAP";
422		break;
423	case 0x97:		/* CN73XX */
424		if (num_cores == 6)	/* Other core counts match generic */
425			core_model = "35";
426		family = "73";
427		if (fus_dat3.cn73xx.l2c_crip == 2)
428			family = "72";
429		if (fus_dat3.cn73xx.nozip
430				&& fus_dat3.cn73xx.nodfa_dte
431				&& fus_dat3.cn73xx.nohna_dte) {
432			if (!fus_dat2.cn73xx.raid_en)
433				suffix = "CP";
434			else
435				suffix = "SCP";
436		} else
437			suffix = "AAP";
438		break;
439	case 0x98:		/* CN75XX */
440		family = "F75";
441		if (fus_dat3.cn78xx.nozip
442		    && fus_dat3.cn78xx.nodfa_dte
443		    && fus_dat3.cn78xx.nohna_dte)
444			suffix = "SCP";
445		else
446			suffix = "AAP";
447		break;
448	default:
449		family = "XX";
450		core_model = "XX";
451		strscpy(pass, "X.X");
452		suffix = "XXX";
453		break;
454	}
455
456	clock_mhz = octeon_get_clock_rate() / 1000000;
457	if (family[0] != '3') {
458		int fuse_base = 384 / 8;
459		if (family[0] == '6')
460			fuse_base = 832 / 8;
461
462		/* Check for model in fuses, overrides normal decode */
463		/* This is _not_ valid for Octeon CN3XXX models */
464		fuse_data |= cvmx_fuse_read_byte(fuse_base + 3);
465		fuse_data = fuse_data << 8;
466		fuse_data |= cvmx_fuse_read_byte(fuse_base + 2);
467		fuse_data = fuse_data << 8;
468		fuse_data |= cvmx_fuse_read_byte(fuse_base + 1);
469		fuse_data = fuse_data << 8;
470		fuse_data |= cvmx_fuse_read_byte(fuse_base);
471		if (fuse_data & 0x7ffff) {
472			int model = fuse_data & 0x3fff;
473			int suffix = (fuse_data >> 14) & 0x1f;
474			if (suffix && model) {
475				/* Have both number and suffix in fuses, so both */
476				sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1);
477				core_model = "";
478				family = fuse_model;
479			} else if (suffix && !model) {
480				/* Only have suffix, so add suffix to 'normal' model number */
481				sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1);
482				core_model = fuse_model;
483			} else {
484				/* Don't have suffix, so just use model from fuses */
485				sprintf(fuse_model, "%d", model);
486				core_model = "";
487				family = fuse_model;
488			}
489		}
490	}
491	sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix);
492	return buffer;
493}
494
495/**
496 * Given the chip processor ID from COP0, this function returns a
497 * string representing the chip model number. The string is of the
498 * form CNXXXXpX.X-FREQ-SUFFIX.
499 * - XXXX = The chip model number
500 * - X.X = Chip pass number
501 * - FREQ = Current frequency in Mhz
502 * - SUFFIX = NSP, EXP, SCP, SSP, or CP
503 *
504 * @chip_id: Chip ID
505 *
506 * Returns Model string
507 */
508const char *__init octeon_model_get_string(uint32_t chip_id)
509{
510	static char buffer[32];
511	return octeon_model_get_string_buffer(chip_id, buffer);
512}
~/ Read-only file preview.