linux/arch/mips/cavium-octeon/executive/octeon-model.c
<<
>>
Prefs
   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