Path: blob/master/arch/mips/cavium-octeon/executive/octeon-model.c
10818 views
/***********************license start***************1* Author: Cavium Networks2*3* Contact: [email protected]4* This file is part of the OCTEON SDK5*6* Copyright (c) 2003-2008 Cavium Networks7*8* This file is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License, Version 2, as10* published by the Free Software Foundation.11*12* This file is distributed in the hope that it will be useful, but13* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty14* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or15* NONINFRINGEMENT. See the GNU General Public License for more16* details.17*18* You should have received a copy of the GNU General Public License19* along with this file; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21* or visit http://www.gnu.org/licenses/.22*23* This file may also be available under a different license from Cavium.24* Contact Cavium Networks for more information25***********************license end**************************************/2627/*28* File defining functions for working with different Octeon29* models.30*/31#include <asm/octeon/octeon.h>3233/**34* Given the chip processor ID from COP0, this function returns a35* string representing the chip model number. The string is of the36* form CNXXXXpX.X-FREQ-SUFFIX.37* - XXXX = The chip model number38* - X.X = Chip pass number39* - FREQ = Current frequency in Mhz40* - SUFFIX = NSP, EXP, SCP, SSP, or CP41*42* @chip_id: Chip ID43*44* Returns Model string45*/46const char *octeon_model_get_string(uint32_t chip_id)47{48static char buffer[32];49return octeon_model_get_string_buffer(chip_id, buffer);50}5152/*53* Version of octeon_model_get_string() that takes buffer as argument,54* as running early in u-boot static/global variables don't work when55* running from flash.56*/57const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)58{59const char *family;60const char *core_model;61char pass[4];62int clock_mhz;63const char *suffix;64union cvmx_l2d_fus3 fus3;65int num_cores;66union cvmx_mio_fus_dat2 fus_dat2;67union cvmx_mio_fus_dat3 fus_dat3;68char fuse_model[10];69uint32_t fuse_data = 0;7071fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);72fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);73fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);7475num_cores = cvmx_octeon_num_cores();7677/* Make sure the non existent devices look disabled */78switch ((chip_id >> 8) & 0xff) {79case 6: /* CN50XX */80case 2: /* CN30XX */81fus_dat3.s.nodfa_dte = 1;82fus_dat3.s.nozip = 1;83break;84case 4: /* CN57XX or CN56XX */85fus_dat3.s.nodfa_dte = 1;86break;87default:88break;89}9091/* Make a guess at the suffix */92/* NSP = everything */93/* EXP = No crypto */94/* SCP = No DFA, No zip */95/* CP = No DFA, No crypto, No zip */96if (fus_dat3.s.nodfa_dte) {97if (fus_dat2.s.nocrypto)98suffix = "CP";99else100suffix = "SCP";101} else if (fus_dat2.s.nocrypto)102suffix = "EXP";103else104suffix = "NSP";105106/*107* Assume pass number is encoded using <5:3><2:0>. Exceptions108* will be fixed later.109*/110sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7);111112/*113* Use the number of cores to determine the last 2 digits of114* the model number. There are some exceptions that are fixed115* later.116*/117switch (num_cores) {118case 16:119core_model = "60";120break;121case 15:122core_model = "58";123break;124case 14:125core_model = "55";126break;127case 13:128core_model = "52";129break;130case 12:131core_model = "50";132break;133case 11:134core_model = "48";135break;136case 10:137core_model = "45";138break;139case 9:140core_model = "42";141break;142case 8:143core_model = "40";144break;145case 7:146core_model = "38";147break;148case 6:149core_model = "34";150break;151case 5:152core_model = "32";153break;154case 4:155core_model = "30";156break;157case 3:158core_model = "25";159break;160case 2:161core_model = "20";162break;163case 1:164core_model = "10";165break;166default:167core_model = "XX";168break;169}170171/* Now figure out the family, the first two digits */172switch ((chip_id >> 8) & 0xff) {173case 0: /* CN38XX, CN37XX or CN36XX */174if (fus3.cn38xx.crip_512k) {175/*176* For some unknown reason, the 16 core one is177* called 37 instead of 36.178*/179if (num_cores >= 16)180family = "37";181else182family = "36";183} else184family = "38";185/*186* This series of chips didn't follow the standard187* pass numbering.188*/189switch (chip_id & 0xf) {190case 0:191strcpy(pass, "1.X");192break;193case 1:194strcpy(pass, "2.X");195break;196case 3:197strcpy(pass, "3.X");198break;199default:200strcpy(pass, "X.X");201break;202}203break;204case 1: /* CN31XX or CN3020 */205if ((chip_id & 0x10) || fus3.cn31xx.crip_128k)206family = "30";207else208family = "31";209/*210* This series of chips didn't follow the standard211* pass numbering.212*/213switch (chip_id & 0xf) {214case 0:215strcpy(pass, "1.0");216break;217case 2:218strcpy(pass, "1.1");219break;220default:221strcpy(pass, "X.X");222break;223}224break;225case 2: /* CN3010 or CN3005 */226family = "30";227/* A chip with half cache is an 05 */228if (fus3.cn30xx.crip_64k)229core_model = "05";230/*231* This series of chips didn't follow the standard232* pass numbering.233*/234switch (chip_id & 0xf) {235case 0:236strcpy(pass, "1.0");237break;238case 2:239strcpy(pass, "1.1");240break;241default:242strcpy(pass, "X.X");243break;244}245break;246case 3: /* CN58XX */247family = "58";248/* Special case. 4 core, no crypto */249if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto)250core_model = "29";251252/* Pass 1 uses different encodings for pass numbers */253if ((chip_id & 0xFF) < 0x8) {254switch (chip_id & 0x3) {255case 0:256strcpy(pass, "1.0");257break;258case 1:259strcpy(pass, "1.1");260break;261case 3:262strcpy(pass, "1.2");263break;264default:265strcpy(pass, "1.X");266break;267}268}269break;270case 4: /* CN57XX, CN56XX, CN55XX, CN54XX */271if (fus_dat2.cn56xx.raid_en) {272if (fus3.cn56xx.crip_1024k)273family = "55";274else275family = "57";276if (fus_dat2.cn56xx.nocrypto)277suffix = "SP";278else279suffix = "SSP";280} else {281if (fus_dat2.cn56xx.nocrypto)282suffix = "CP";283else {284suffix = "NSP";285if (fus_dat3.s.nozip)286suffix = "SCP";287}288if (fus3.cn56xx.crip_1024k)289family = "54";290else291family = "56";292}293break;294case 6: /* CN50XX */295family = "50";296break;297case 7: /* CN52XX */298if (fus3.cn52xx.crip_256k)299family = "51";300else301family = "52";302break;303default:304family = "XX";305core_model = "XX";306strcpy(pass, "X.X");307suffix = "XXX";308break;309}310311clock_mhz = octeon_get_clock_rate() / 1000000;312313if (family[0] != '3') {314/* Check for model in fuses, overrides normal decode */315/* This is _not_ valid for Octeon CN3XXX models */316fuse_data |= cvmx_fuse_read_byte(51);317fuse_data = fuse_data << 8;318fuse_data |= cvmx_fuse_read_byte(50);319fuse_data = fuse_data << 8;320fuse_data |= cvmx_fuse_read_byte(49);321fuse_data = fuse_data << 8;322fuse_data |= cvmx_fuse_read_byte(48);323if (fuse_data & 0x7ffff) {324int model = fuse_data & 0x3fff;325int suffix = (fuse_data >> 14) & 0x1f;326if (suffix && model) {327/*328* Have both number and suffix in329* fuses, so both330*/331sprintf(fuse_model, "%d%c",332model, 'A' + suffix - 1);333core_model = "";334family = fuse_model;335} else if (suffix && !model) {336/*337* Only have suffix, so add suffix to338* 'normal' model number.339*/340sprintf(fuse_model, "%s%c", core_model,341'A' + suffix - 1);342core_model = fuse_model;343} else {344/*345* Don't have suffix, so just use346* model from fuses.347*/348sprintf(fuse_model, "%d", model);349core_model = "";350family = fuse_model;351}352}353}354sprintf(buffer, "CN%s%sp%s-%d-%s",355family, core_model, pass, clock_mhz, suffix);356return buffer;357}358359360