158f07778SDavid Daney /***********************license start*************** 258f07778SDavid Daney * Author: Cavium Networks 358f07778SDavid Daney * 458f07778SDavid Daney * Contact: support@caviumnetworks.com 558f07778SDavid Daney * This file is part of the OCTEON SDK 658f07778SDavid Daney * 7751c9f68SDavid Daney * Copyright (c) 2003-2010 Cavium Networks 858f07778SDavid Daney * 958f07778SDavid Daney * This file is free software; you can redistribute it and/or modify 1058f07778SDavid Daney * it under the terms of the GNU General Public License, Version 2, as 1158f07778SDavid Daney * published by the Free Software Foundation. 1258f07778SDavid Daney * 1358f07778SDavid Daney * This file is distributed in the hope that it will be useful, but 1458f07778SDavid Daney * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 1558f07778SDavid Daney * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 1658f07778SDavid Daney * NONINFRINGEMENT. See the GNU General Public License for more 1758f07778SDavid Daney * details. 1858f07778SDavid Daney * 1958f07778SDavid Daney * You should have received a copy of the GNU General Public License 2058f07778SDavid Daney * along with this file; if not, write to the Free Software 2158f07778SDavid Daney * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2258f07778SDavid Daney * or visit http://www.gnu.org/licenses/. 2358f07778SDavid Daney * 2458f07778SDavid Daney * This file may also be available under a different license from Cavium. 2558f07778SDavid Daney * Contact Cavium Networks for more information 2658f07778SDavid Daney ***********************license end**************************************/ 2758f07778SDavid Daney 2858f07778SDavid Daney #include <asm/octeon/octeon.h> 2958f07778SDavid Daney 30011f3c6cSAaro Koskinen enum octeon_feature_bits __octeon_feature_bits __read_mostly; 31011f3c6cSAaro Koskinen EXPORT_SYMBOL_GPL(__octeon_feature_bits); 32011f3c6cSAaro Koskinen 3358f07778SDavid Daney /** 340f24017aSAaro Koskinen * Read a byte of fuse data 350f24017aSAaro Koskinen * @byte_addr: address to read 360f24017aSAaro Koskinen * 370f24017aSAaro Koskinen * Returns fuse value: 0 or 1 380f24017aSAaro Koskinen */ 39da85e364SAaro Koskinen static uint8_t __init cvmx_fuse_read_byte(int byte_addr) 400f24017aSAaro Koskinen { 410f24017aSAaro Koskinen union cvmx_mio_fus_rcmd read_cmd; 420f24017aSAaro Koskinen 430f24017aSAaro Koskinen read_cmd.u64 = 0; 440f24017aSAaro Koskinen read_cmd.s.addr = byte_addr; 450f24017aSAaro Koskinen read_cmd.s.pend = 1; 460f24017aSAaro Koskinen cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64); 470f24017aSAaro Koskinen while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD)) 480f24017aSAaro Koskinen && read_cmd.s.pend) 490f24017aSAaro Koskinen ; 500f24017aSAaro Koskinen return read_cmd.s.dat; 510f24017aSAaro Koskinen } 520f24017aSAaro Koskinen 5358f07778SDavid Daney /* 5458f07778SDavid Daney * Version of octeon_model_get_string() that takes buffer as argument, 5558f07778SDavid Daney * as running early in u-boot static/global variables don't work when 5658f07778SDavid Daney * running from flash. 5758f07778SDavid Daney */ 58da85e364SAaro Koskinen static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, 59da85e364SAaro Koskinen char *buffer) 6058f07778SDavid Daney { 6158f07778SDavid Daney const char *family; 6258f07778SDavid Daney const char *core_model; 6358f07778SDavid Daney char pass[4]; 6458f07778SDavid Daney int clock_mhz; 6558f07778SDavid Daney const char *suffix; 6658f07778SDavid Daney union cvmx_l2d_fus3 fus3; 6758f07778SDavid Daney int num_cores; 6858f07778SDavid Daney union cvmx_mio_fus_dat2 fus_dat2; 6958f07778SDavid Daney union cvmx_mio_fus_dat3 fus_dat3; 7058f07778SDavid Daney char fuse_model[10]; 7158f07778SDavid Daney uint32_t fuse_data = 0; 7258f07778SDavid Daney 73751c9f68SDavid Daney fus3.u64 = 0; 74*182a6d1cSDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN5XXX)) 7558f07778SDavid Daney fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); 7658f07778SDavid Daney fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); 7758f07778SDavid Daney fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); 78*182a6d1cSDavid Daney num_cores = cvmx_octeon_num_cores(); 7958f07778SDavid Daney 8025985edcSLucas De Marchi /* Make sure the non existent devices look disabled */ 8158f07778SDavid Daney switch ((chip_id >> 8) & 0xff) { 8258f07778SDavid Daney case 6: /* CN50XX */ 8358f07778SDavid Daney case 2: /* CN30XX */ 8458f07778SDavid Daney fus_dat3.s.nodfa_dte = 1; 8558f07778SDavid Daney fus_dat3.s.nozip = 1; 8658f07778SDavid Daney break; 8758f07778SDavid Daney case 4: /* CN57XX or CN56XX */ 8858f07778SDavid Daney fus_dat3.s.nodfa_dte = 1; 8958f07778SDavid Daney break; 9058f07778SDavid Daney default: 9158f07778SDavid Daney break; 9258f07778SDavid Daney } 9358f07778SDavid Daney 9458f07778SDavid Daney /* Make a guess at the suffix */ 9558f07778SDavid Daney /* NSP = everything */ 9658f07778SDavid Daney /* EXP = No crypto */ 9758f07778SDavid Daney /* SCP = No DFA, No zip */ 9858f07778SDavid Daney /* CP = No DFA, No crypto, No zip */ 9958f07778SDavid Daney if (fus_dat3.s.nodfa_dte) { 10058f07778SDavid Daney if (fus_dat2.s.nocrypto) 10158f07778SDavid Daney suffix = "CP"; 10258f07778SDavid Daney else 10358f07778SDavid Daney suffix = "SCP"; 10458f07778SDavid Daney } else if (fus_dat2.s.nocrypto) 10558f07778SDavid Daney suffix = "EXP"; 10658f07778SDavid Daney else 10758f07778SDavid Daney suffix = "NSP"; 10858f07778SDavid Daney 109011f3c6cSAaro Koskinen if (!fus_dat2.s.nocrypto) 110011f3c6cSAaro Koskinen __octeon_feature_bits |= OCTEON_HAS_CRYPTO; 111011f3c6cSAaro Koskinen 11258f07778SDavid Daney /* 11358f07778SDavid Daney * Assume pass number is encoded using <5:3><2:0>. Exceptions 11458f07778SDavid Daney * will be fixed later. 11558f07778SDavid Daney */ 116751c9f68SDavid Daney sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7); 11758f07778SDavid Daney 11858f07778SDavid Daney /* 11958f07778SDavid Daney * Use the number of cores to determine the last 2 digits of 12058f07778SDavid Daney * the model number. There are some exceptions that are fixed 12158f07778SDavid Daney * later. 12258f07778SDavid Daney */ 12358f07778SDavid Daney switch (num_cores) { 124*182a6d1cSDavid Daney case 48: 125*182a6d1cSDavid Daney core_model = "90"; 126*182a6d1cSDavid Daney break; 127*182a6d1cSDavid Daney case 44: 128*182a6d1cSDavid Daney core_model = "88"; 129*182a6d1cSDavid Daney break; 130*182a6d1cSDavid Daney case 40: 131*182a6d1cSDavid Daney core_model = "85"; 132*182a6d1cSDavid Daney break; 133751c9f68SDavid Daney case 32: 134751c9f68SDavid Daney core_model = "80"; 135751c9f68SDavid Daney break; 136751c9f68SDavid Daney case 24: 137751c9f68SDavid Daney core_model = "70"; 138751c9f68SDavid Daney break; 13958f07778SDavid Daney case 16: 14058f07778SDavid Daney core_model = "60"; 14158f07778SDavid Daney break; 14258f07778SDavid Daney case 15: 14358f07778SDavid Daney core_model = "58"; 14458f07778SDavid Daney break; 14558f07778SDavid Daney case 14: 14658f07778SDavid Daney core_model = "55"; 14758f07778SDavid Daney break; 14858f07778SDavid Daney case 13: 14958f07778SDavid Daney core_model = "52"; 15058f07778SDavid Daney break; 15158f07778SDavid Daney case 12: 15258f07778SDavid Daney core_model = "50"; 15358f07778SDavid Daney break; 15458f07778SDavid Daney case 11: 15558f07778SDavid Daney core_model = "48"; 15658f07778SDavid Daney break; 15758f07778SDavid Daney case 10: 15858f07778SDavid Daney core_model = "45"; 15958f07778SDavid Daney break; 16058f07778SDavid Daney case 9: 16158f07778SDavid Daney core_model = "42"; 16258f07778SDavid Daney break; 16358f07778SDavid Daney case 8: 16458f07778SDavid Daney core_model = "40"; 16558f07778SDavid Daney break; 16658f07778SDavid Daney case 7: 16758f07778SDavid Daney core_model = "38"; 16858f07778SDavid Daney break; 16958f07778SDavid Daney case 6: 17058f07778SDavid Daney core_model = "34"; 17158f07778SDavid Daney break; 17258f07778SDavid Daney case 5: 17358f07778SDavid Daney core_model = "32"; 17458f07778SDavid Daney break; 17558f07778SDavid Daney case 4: 17658f07778SDavid Daney core_model = "30"; 17758f07778SDavid Daney break; 17858f07778SDavid Daney case 3: 17958f07778SDavid Daney core_model = "25"; 18058f07778SDavid Daney break; 18158f07778SDavid Daney case 2: 18258f07778SDavid Daney core_model = "20"; 18358f07778SDavid Daney break; 18458f07778SDavid Daney case 1: 18558f07778SDavid Daney core_model = "10"; 18658f07778SDavid Daney break; 18758f07778SDavid Daney default: 18858f07778SDavid Daney core_model = "XX"; 18958f07778SDavid Daney break; 19058f07778SDavid Daney } 19158f07778SDavid Daney 19258f07778SDavid Daney /* Now figure out the family, the first two digits */ 19358f07778SDavid Daney switch ((chip_id >> 8) & 0xff) { 19458f07778SDavid Daney case 0: /* CN38XX, CN37XX or CN36XX */ 19558f07778SDavid Daney if (fus3.cn38xx.crip_512k) { 19658f07778SDavid Daney /* 19758f07778SDavid Daney * For some unknown reason, the 16 core one is 19858f07778SDavid Daney * called 37 instead of 36. 19958f07778SDavid Daney */ 20058f07778SDavid Daney if (num_cores >= 16) 20158f07778SDavid Daney family = "37"; 20258f07778SDavid Daney else 20358f07778SDavid Daney family = "36"; 20458f07778SDavid Daney } else 20558f07778SDavid Daney family = "38"; 20658f07778SDavid Daney /* 20758f07778SDavid Daney * This series of chips didn't follow the standard 20858f07778SDavid Daney * pass numbering. 20958f07778SDavid Daney */ 21058f07778SDavid Daney switch (chip_id & 0xf) { 21158f07778SDavid Daney case 0: 21258f07778SDavid Daney strcpy(pass, "1.X"); 21358f07778SDavid Daney break; 21458f07778SDavid Daney case 1: 21558f07778SDavid Daney strcpy(pass, "2.X"); 21658f07778SDavid Daney break; 21758f07778SDavid Daney case 3: 21858f07778SDavid Daney strcpy(pass, "3.X"); 21958f07778SDavid Daney break; 22058f07778SDavid Daney default: 22158f07778SDavid Daney strcpy(pass, "X.X"); 22258f07778SDavid Daney break; 22358f07778SDavid Daney } 22458f07778SDavid Daney break; 22558f07778SDavid Daney case 1: /* CN31XX or CN3020 */ 22658f07778SDavid Daney if ((chip_id & 0x10) || fus3.cn31xx.crip_128k) 22758f07778SDavid Daney family = "30"; 22858f07778SDavid Daney else 22958f07778SDavid Daney family = "31"; 23058f07778SDavid Daney /* 23158f07778SDavid Daney * This series of chips didn't follow the standard 23258f07778SDavid Daney * pass numbering. 23358f07778SDavid Daney */ 23458f07778SDavid Daney switch (chip_id & 0xf) { 23558f07778SDavid Daney case 0: 23658f07778SDavid Daney strcpy(pass, "1.0"); 23758f07778SDavid Daney break; 23858f07778SDavid Daney case 2: 23958f07778SDavid Daney strcpy(pass, "1.1"); 24058f07778SDavid Daney break; 24158f07778SDavid Daney default: 24258f07778SDavid Daney strcpy(pass, "X.X"); 24358f07778SDavid Daney break; 24458f07778SDavid Daney } 24558f07778SDavid Daney break; 24658f07778SDavid Daney case 2: /* CN3010 or CN3005 */ 24758f07778SDavid Daney family = "30"; 24858f07778SDavid Daney /* A chip with half cache is an 05 */ 24958f07778SDavid Daney if (fus3.cn30xx.crip_64k) 25058f07778SDavid Daney core_model = "05"; 25158f07778SDavid Daney /* 25258f07778SDavid Daney * This series of chips didn't follow the standard 25358f07778SDavid Daney * pass numbering. 25458f07778SDavid Daney */ 25558f07778SDavid Daney switch (chip_id & 0xf) { 25658f07778SDavid Daney case 0: 25758f07778SDavid Daney strcpy(pass, "1.0"); 25858f07778SDavid Daney break; 25958f07778SDavid Daney case 2: 26058f07778SDavid Daney strcpy(pass, "1.1"); 26158f07778SDavid Daney break; 26258f07778SDavid Daney default: 26358f07778SDavid Daney strcpy(pass, "X.X"); 26458f07778SDavid Daney break; 26558f07778SDavid Daney } 26658f07778SDavid Daney break; 26758f07778SDavid Daney case 3: /* CN58XX */ 26858f07778SDavid Daney family = "58"; 269751c9f68SDavid Daney /* Special case. 4 core, half cache (CP with half cache) */ 270751c9f68SDavid Daney if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2)) 27158f07778SDavid Daney core_model = "29"; 27258f07778SDavid Daney 27358f07778SDavid Daney /* Pass 1 uses different encodings for pass numbers */ 27458f07778SDavid Daney if ((chip_id & 0xFF) < 0x8) { 27558f07778SDavid Daney switch (chip_id & 0x3) { 27658f07778SDavid Daney case 0: 27758f07778SDavid Daney strcpy(pass, "1.0"); 27858f07778SDavid Daney break; 27958f07778SDavid Daney case 1: 28058f07778SDavid Daney strcpy(pass, "1.1"); 28158f07778SDavid Daney break; 28258f07778SDavid Daney case 3: 28358f07778SDavid Daney strcpy(pass, "1.2"); 28458f07778SDavid Daney break; 28558f07778SDavid Daney default: 28658f07778SDavid Daney strcpy(pass, "1.X"); 28758f07778SDavid Daney break; 28858f07778SDavid Daney } 28958f07778SDavid Daney } 29058f07778SDavid Daney break; 29158f07778SDavid Daney case 4: /* CN57XX, CN56XX, CN55XX, CN54XX */ 29258f07778SDavid Daney if (fus_dat2.cn56xx.raid_en) { 29358f07778SDavid Daney if (fus3.cn56xx.crip_1024k) 29458f07778SDavid Daney family = "55"; 29558f07778SDavid Daney else 29658f07778SDavid Daney family = "57"; 29758f07778SDavid Daney if (fus_dat2.cn56xx.nocrypto) 29858f07778SDavid Daney suffix = "SP"; 29958f07778SDavid Daney else 30058f07778SDavid Daney suffix = "SSP"; 30158f07778SDavid Daney } else { 30258f07778SDavid Daney if (fus_dat2.cn56xx.nocrypto) 30358f07778SDavid Daney suffix = "CP"; 30458f07778SDavid Daney else { 30558f07778SDavid Daney suffix = "NSP"; 30658f07778SDavid Daney if (fus_dat3.s.nozip) 30758f07778SDavid Daney suffix = "SCP"; 308751c9f68SDavid Daney 309*182a6d1cSDavid Daney if (fus_dat3.cn56xx.bar2_en) 310751c9f68SDavid Daney suffix = "NSPB2"; 31158f07778SDavid Daney } 31258f07778SDavid Daney if (fus3.cn56xx.crip_1024k) 31358f07778SDavid Daney family = "54"; 31458f07778SDavid Daney else 31558f07778SDavid Daney family = "56"; 31658f07778SDavid Daney } 31758f07778SDavid Daney break; 31858f07778SDavid Daney case 6: /* CN50XX */ 31958f07778SDavid Daney family = "50"; 32058f07778SDavid Daney break; 32158f07778SDavid Daney case 7: /* CN52XX */ 32258f07778SDavid Daney if (fus3.cn52xx.crip_256k) 32358f07778SDavid Daney family = "51"; 32458f07778SDavid Daney else 32558f07778SDavid Daney family = "52"; 32658f07778SDavid Daney break; 327751c9f68SDavid Daney case 0x93: /* CN61XX */ 328751c9f68SDavid Daney family = "61"; 329751c9f68SDavid Daney if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto) 330751c9f68SDavid Daney suffix = "AP"; 331751c9f68SDavid Daney if (fus_dat2.cn61xx.nocrypto) 332751c9f68SDavid Daney suffix = "CP"; 333751c9f68SDavid Daney else if (fus_dat2.cn61xx.dorm_crypto) 334751c9f68SDavid Daney suffix = "DAP"; 335751c9f68SDavid Daney else if (fus_dat3.cn61xx.nozip) 336751c9f68SDavid Daney suffix = "SCP"; 337751c9f68SDavid Daney break; 338751c9f68SDavid Daney case 0x90: /* CN63XX */ 339751c9f68SDavid Daney family = "63"; 340751c9f68SDavid Daney if (fus_dat3.s.l2c_crip == 2) 341751c9f68SDavid Daney family = "62"; 342751c9f68SDavid Daney if (num_cores == 6) /* Other core counts match generic */ 343751c9f68SDavid Daney core_model = "35"; 344751c9f68SDavid Daney if (fus_dat2.cn63xx.nocrypto) 345751c9f68SDavid Daney suffix = "CP"; 346751c9f68SDavid Daney else if (fus_dat2.cn63xx.dorm_crypto) 347751c9f68SDavid Daney suffix = "DAP"; 348751c9f68SDavid Daney else if (fus_dat3.cn63xx.nozip) 349751c9f68SDavid Daney suffix = "SCP"; 350751c9f68SDavid Daney else 351751c9f68SDavid Daney suffix = "AAP"; 352751c9f68SDavid Daney break; 353751c9f68SDavid Daney case 0x92: /* CN66XX */ 354751c9f68SDavid Daney family = "66"; 355751c9f68SDavid Daney if (num_cores == 6) /* Other core counts match generic */ 356751c9f68SDavid Daney core_model = "35"; 357751c9f68SDavid Daney if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto) 358751c9f68SDavid Daney suffix = "AP"; 359751c9f68SDavid Daney if (fus_dat2.cn66xx.nocrypto) 360751c9f68SDavid Daney suffix = "CP"; 361751c9f68SDavid Daney else if (fus_dat2.cn66xx.dorm_crypto) 362751c9f68SDavid Daney suffix = "DAP"; 363751c9f68SDavid Daney else if (fus_dat3.cn66xx.nozip) 364751c9f68SDavid Daney suffix = "SCP"; 365751c9f68SDavid Daney else 366751c9f68SDavid Daney suffix = "AAP"; 367751c9f68SDavid Daney break; 368751c9f68SDavid Daney case 0x91: /* CN68XX */ 369751c9f68SDavid Daney family = "68"; 370751c9f68SDavid Daney if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip) 371751c9f68SDavid Daney suffix = "CP"; 372751c9f68SDavid Daney else if (fus_dat2.cn68xx.dorm_crypto) 373751c9f68SDavid Daney suffix = "DAP"; 374751c9f68SDavid Daney else if (fus_dat3.cn68xx.nozip) 375751c9f68SDavid Daney suffix = "SCP"; 376751c9f68SDavid Daney else if (fus_dat2.cn68xx.nocrypto) 377751c9f68SDavid Daney suffix = "SP"; 378751c9f68SDavid Daney else 379751c9f68SDavid Daney suffix = "AAP"; 380751c9f68SDavid Daney break; 381*182a6d1cSDavid Daney case 0x94: /* CNF71XX */ 382*182a6d1cSDavid Daney family = "F71"; 383*182a6d1cSDavid Daney if (fus_dat3.cnf71xx.nozip) 384*182a6d1cSDavid Daney suffix = "SCP"; 385*182a6d1cSDavid Daney else 386*182a6d1cSDavid Daney suffix = "AAP"; 387*182a6d1cSDavid Daney break; 388*182a6d1cSDavid Daney case 0x95: /* CN78XX */ 389*182a6d1cSDavid Daney if (num_cores == 6) /* Other core counts match generic */ 390*182a6d1cSDavid Daney core_model = "35"; 391*182a6d1cSDavid Daney if (OCTEON_IS_MODEL(OCTEON_CN76XX)) 392*182a6d1cSDavid Daney family = "76"; 393*182a6d1cSDavid Daney else 394*182a6d1cSDavid Daney family = "78"; 395*182a6d1cSDavid Daney if (fus_dat3.cn78xx.l2c_crip == 2) 396*182a6d1cSDavid Daney family = "77"; 397*182a6d1cSDavid Daney if (fus_dat3.cn78xx.nozip 398*182a6d1cSDavid Daney && fus_dat3.cn78xx.nodfa_dte 399*182a6d1cSDavid Daney && fus_dat3.cn78xx.nohna_dte) { 400*182a6d1cSDavid Daney if (fus_dat3.cn78xx.nozip && 401*182a6d1cSDavid Daney !fus_dat2.cn78xx.raid_en && 402*182a6d1cSDavid Daney fus_dat3.cn78xx.nohna_dte) { 403*182a6d1cSDavid Daney suffix = "CP"; 404*182a6d1cSDavid Daney } else { 405*182a6d1cSDavid Daney suffix = "SCP"; 406*182a6d1cSDavid Daney } 407*182a6d1cSDavid Daney } else if (fus_dat2.cn78xx.raid_en == 0) 408*182a6d1cSDavid Daney suffix = "HCP"; 409*182a6d1cSDavid Daney else 410*182a6d1cSDavid Daney suffix = "AAP"; 411*182a6d1cSDavid Daney break; 412*182a6d1cSDavid Daney case 0x96: /* CN70XX */ 413*182a6d1cSDavid Daney family = "70"; 414*182a6d1cSDavid Daney if (cvmx_read_csr(CVMX_MIO_FUS_PDF) & (0x1ULL << 32)) 415*182a6d1cSDavid Daney family = "71"; 416*182a6d1cSDavid Daney if (fus_dat2.cn70xx.nocrypto) 417*182a6d1cSDavid Daney suffix = "CP"; 418*182a6d1cSDavid Daney else if (fus_dat3.cn70xx.nodfa_dte) 419*182a6d1cSDavid Daney suffix = "SCP"; 420*182a6d1cSDavid Daney else 421*182a6d1cSDavid Daney suffix = "AAP"; 422*182a6d1cSDavid Daney break; 423*182a6d1cSDavid Daney case 0x97: /* CN73XX */ 424*182a6d1cSDavid Daney if (num_cores == 6) /* Other core counts match generic */ 425*182a6d1cSDavid Daney core_model = "35"; 426*182a6d1cSDavid Daney family = "73"; 427*182a6d1cSDavid Daney if (fus_dat3.cn73xx.l2c_crip == 2) 428*182a6d1cSDavid Daney family = "72"; 429*182a6d1cSDavid Daney if (fus_dat3.cn73xx.nozip 430*182a6d1cSDavid Daney && fus_dat3.cn73xx.nodfa_dte 431*182a6d1cSDavid Daney && fus_dat3.cn73xx.nohna_dte) { 432*182a6d1cSDavid Daney if (!fus_dat2.cn73xx.raid_en) 433*182a6d1cSDavid Daney suffix = "CP"; 434*182a6d1cSDavid Daney else 435*182a6d1cSDavid Daney suffix = "SCP"; 436*182a6d1cSDavid Daney } else 437*182a6d1cSDavid Daney suffix = "AAP"; 438*182a6d1cSDavid Daney break; 439*182a6d1cSDavid Daney case 0x98: /* CN75XX */ 440*182a6d1cSDavid Daney family = "F75"; 441*182a6d1cSDavid Daney if (fus_dat3.cn78xx.nozip 442*182a6d1cSDavid Daney && fus_dat3.cn78xx.nodfa_dte 443*182a6d1cSDavid Daney && fus_dat3.cn78xx.nohna_dte) 444*182a6d1cSDavid Daney suffix = "SCP"; 445*182a6d1cSDavid Daney else 446*182a6d1cSDavid Daney suffix = "AAP"; 447*182a6d1cSDavid Daney break; 44858f07778SDavid Daney default: 44958f07778SDavid Daney family = "XX"; 45058f07778SDavid Daney core_model = "XX"; 45158f07778SDavid Daney strcpy(pass, "X.X"); 45258f07778SDavid Daney suffix = "XXX"; 45358f07778SDavid Daney break; 45458f07778SDavid Daney } 45558f07778SDavid Daney 45658f07778SDavid Daney clock_mhz = octeon_get_clock_rate() / 1000000; 45758f07778SDavid Daney if (family[0] != '3') { 458751c9f68SDavid Daney int fuse_base = 384 / 8; 459751c9f68SDavid Daney if (family[0] == '6') 460751c9f68SDavid Daney fuse_base = 832 / 8; 461751c9f68SDavid Daney 46258f07778SDavid Daney /* Check for model in fuses, overrides normal decode */ 46358f07778SDavid Daney /* This is _not_ valid for Octeon CN3XXX models */ 464751c9f68SDavid Daney fuse_data |= cvmx_fuse_read_byte(fuse_base + 3); 46558f07778SDavid Daney fuse_data = fuse_data << 8; 466751c9f68SDavid Daney fuse_data |= cvmx_fuse_read_byte(fuse_base + 2); 46758f07778SDavid Daney fuse_data = fuse_data << 8; 468751c9f68SDavid Daney fuse_data |= cvmx_fuse_read_byte(fuse_base + 1); 46958f07778SDavid Daney fuse_data = fuse_data << 8; 470751c9f68SDavid Daney fuse_data |= cvmx_fuse_read_byte(fuse_base); 47158f07778SDavid Daney if (fuse_data & 0x7ffff) { 47258f07778SDavid Daney int model = fuse_data & 0x3fff; 47358f07778SDavid Daney int suffix = (fuse_data >> 14) & 0x1f; 47458f07778SDavid Daney if (suffix && model) { 475751c9f68SDavid Daney /* Have both number and suffix in fuses, so both */ 476751c9f68SDavid Daney sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1); 47758f07778SDavid Daney core_model = ""; 47858f07778SDavid Daney family = fuse_model; 47958f07778SDavid Daney } else if (suffix && !model) { 480751c9f68SDavid Daney /* Only have suffix, so add suffix to 'normal' model number */ 481751c9f68SDavid Daney sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1); 48258f07778SDavid Daney core_model = fuse_model; 48358f07778SDavid Daney } else { 484751c9f68SDavid Daney /* Don't have suffix, so just use model from fuses */ 48558f07778SDavid Daney sprintf(fuse_model, "%d", model); 48658f07778SDavid Daney core_model = ""; 48758f07778SDavid Daney family = fuse_model; 48858f07778SDavid Daney } 48958f07778SDavid Daney } 49058f07778SDavid Daney } 491751c9f68SDavid Daney sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix); 49258f07778SDavid Daney return buffer; 49358f07778SDavid Daney } 494653e0528SAaro Koskinen 495653e0528SAaro Koskinen /** 496653e0528SAaro Koskinen * Given the chip processor ID from COP0, this function returns a 497653e0528SAaro Koskinen * string representing the chip model number. The string is of the 498653e0528SAaro Koskinen * form CNXXXXpX.X-FREQ-SUFFIX. 499653e0528SAaro Koskinen * - XXXX = The chip model number 500653e0528SAaro Koskinen * - X.X = Chip pass number 501653e0528SAaro Koskinen * - FREQ = Current frequency in Mhz 502653e0528SAaro Koskinen * - SUFFIX = NSP, EXP, SCP, SSP, or CP 503653e0528SAaro Koskinen * 504653e0528SAaro Koskinen * @chip_id: Chip ID 505653e0528SAaro Koskinen * 506653e0528SAaro Koskinen * Returns Model string 507653e0528SAaro Koskinen */ 508da85e364SAaro Koskinen const char *__init octeon_model_get_string(uint32_t chip_id) 509653e0528SAaro Koskinen { 510653e0528SAaro Koskinen static char buffer[32]; 511653e0528SAaro Koskinen return octeon_model_get_string_buffer(chip_id, buffer); 512653e0528SAaro Koskinen } 513