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
  30/**
  31 * Given the chip processor ID from COP0, this function returns a
  32 * string representing the chip model number. The string is of the
  33 * form CNXXXXpX.X-FREQ-SUFFIX.
  34 * - XXXX = The chip model number
  35 * - X.X = Chip pass number
  36 * - FREQ = Current frequency in Mhz
  37 * - SUFFIX = NSP, EXP, SCP, SSP, or CP
  38 *
  39 * @chip_id: Chip ID
  40 *
  41 * Returns Model string
  42 */
  43const char *octeon_model_get_string(uint32_t chip_id)
  44{
  45        static char buffer[32];
  46        return octeon_model_get_string_buffer(chip_id, buffer);
  47}
  48
  49/*
  50 * Version of octeon_model_get_string() that takes buffer as argument,
  51 * as running early in u-boot static/global variables don't work when
  52 * running from flash.
  53 */
  54const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
  55{
  56        const char *family;
  57        const char *core_model;
  58        char pass[4];
  59        int clock_mhz;
  60        const char *suffix;
  61        union cvmx_l2d_fus3 fus3;
  62        int num_cores;
  63        union cvmx_mio_fus_dat2 fus_dat2;
  64        union cvmx_mio_fus_dat3 fus_dat3;
  65        char fuse_model[10];
  66        uint32_t fuse_data = 0;
  67
  68        fus3.u64 = 0;
  69        if (!OCTEON_IS_MODEL(OCTEON_CN6XXX))
  70                fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
  71        fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
  72        fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
  73        num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE));
  74
  75        /* Make sure the non existent devices look disabled */
  76        switch ((chip_id >> 8) & 0xff) {
  77        case 6:         /* CN50XX */
  78        case 2:         /* CN30XX */
  79                fus_dat3.s.nodfa_dte = 1;
  80                fus_dat3.s.nozip = 1;
  81                break;
  82        case 4:         /* CN57XX or CN56XX */
  83                fus_dat3.s.nodfa_dte = 1;
  84                break;
  85        default:
  86                break;
  87        }
  88
  89        /* Make a guess at the suffix */
  90        /* NSP = everything */
  91        /* EXP = No crypto */
  92        /* SCP = No DFA, No zip */
  93        /* CP = No DFA, No crypto, No zip */
  94        if (fus_dat3.s.nodfa_dte) {
  95                if (fus_dat2.s.nocrypto)
  96                        suffix = "CP";
  97                else
  98                        suffix = "SCP";
  99        } else if (fus_dat2.s.nocrypto)
 100                suffix = "EXP";
 101        else
 102                suffix = "NSP";
 103
 104        /*
 105         * Assume pass number is encoded using <5:3><2:0>. Exceptions
 106         * will be fixed later.
 107         */
 108        sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7);
 109
 110        /*
 111         * Use the number of cores to determine the last 2 digits of
 112         * the model number. There are some exceptions that are fixed
 113         * later.
 114         */
 115        switch (num_cores) {
 116        case 32:
 117                core_model = "80";
 118                break;
 119        case 24:
 120                core_model = "70";
 121                break;
 122        case 16:
 123                core_model = "60";
 124                break;
 125        case 15:
 126                core_model = "58";
 127                break;
 128        case 14:
 129                core_model = "55";
 130                break;
 131        case 13:
 132                core_model = "52";
 133                break;
 134        case 12:
 135                core_model = "50";
 136                break;
 137        case 11:
 138                core_model = "48";
 139                break;
 140        case 10:
 141                core_model = "45";
 142                break;
 143        case 9:
 144                core_model = "42";
 145                break;
 146        case 8:
 147                core_model = "40";
 148                break;
 149        case 7:
 150                core_model = "38";
 151                break;
 152        case 6:
 153                core_model = "34";
 154                break;
 155        case 5:
 156                core_model = "32";
 157                break;
 158        case 4:
 159                core_model = "30";
 160                break;
 161        case 3:
 162                core_model = "25";
 163                break;
 164        case 2:
 165                core_model = "20";
 166                break;
 167        case 1:
 168                core_model = "10";
 169                break;
 170        default:
 171                core_model = "XX";
 172                break;
 173        }
 174
 175        /* Now figure out the family, the first two digits */
 176        switch ((chip_id >> 8) & 0xff) {
 177        case 0:         /* CN38XX, CN37XX or CN36XX */
 178                if (fus3.cn38xx.crip_512k) {
 179                        /*
 180                         * For some unknown reason, the 16 core one is
 181                         * called 37 instead of 36.
 182                         */
 183                        if (num_cores >= 16)
 184                                family = "37";
 185                        else
 186                                family = "36";
 187                } else
 188                        family = "38";
 189                /*
 190                 * This series of chips didn't follow the standard
 191                 * pass numbering.
 192                 */
 193                switch (chip_id & 0xf) {
 194                case 0:
 195                        strcpy(pass, "1.X");
 196                        break;
 197                case 1:
 198                        strcpy(pass, "2.X");
 199                        break;
 200                case 3:
 201                        strcpy(pass, "3.X");
 202                        break;
 203                default:
 204                        strcpy(pass, "X.X");
 205                        break;
 206                }
 207                break;
 208        case 1:         /* CN31XX or CN3020 */
 209                if ((chip_id & 0x10) || fus3.cn31xx.crip_128k)
 210                        family = "30";
 211                else
 212                        family = "31";
 213                /*
 214                 * This series of chips didn't follow the standard
 215                 * pass numbering.
 216                 */
 217                switch (chip_id & 0xf) {
 218                case 0:
 219                        strcpy(pass, "1.0");
 220                        break;
 221                case 2:
 222                        strcpy(pass, "1.1");
 223                        break;
 224                default:
 225                        strcpy(pass, "X.X");
 226                        break;
 227                }
 228                break;
 229        case 2:         /* CN3010 or CN3005 */
 230                family = "30";
 231                /* A chip with half cache is an 05 */
 232                if (fus3.cn30xx.crip_64k)
 233                        core_model = "05";
 234                /*
 235                 * This series of chips didn't follow the standard
 236                 * pass numbering.
 237                 */
 238                switch (chip_id & 0xf) {
 239                case 0:
 240                        strcpy(pass, "1.0");
 241                        break;
 242                case 2:
 243                        strcpy(pass, "1.1");
 244                        break;
 245                default:
 246                        strcpy(pass, "X.X");
 247                        break;
 248                }
 249                break;
 250        case 3:         /* CN58XX */
 251                family = "58";
 252                /* Special case. 4 core, half cache (CP with half cache) */
 253                if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2))
 254                        core_model = "29";
 255
 256                /* Pass 1 uses different encodings for pass numbers */
 257                if ((chip_id & 0xFF) < 0x8) {
 258                        switch (chip_id & 0x3) {
 259                        case 0:
 260                                strcpy(pass, "1.0");
 261                                break;
 262                        case 1:
 263                                strcpy(pass, "1.1");
 264                                break;
 265                        case 3:
 266                                strcpy(pass, "1.2");
 267                                break;
 268                        default:
 269                                strcpy(pass, "1.X");
 270                                break;
 271                        }
 272                }
 273                break;
 274        case 4:         /* CN57XX, CN56XX, CN55XX, CN54XX */
 275                if (fus_dat2.cn56xx.raid_en) {
 276                        if (fus3.cn56xx.crip_1024k)
 277                                family = "55";
 278                        else
 279                                family = "57";
 280                        if (fus_dat2.cn56xx.nocrypto)
 281                                suffix = "SP";
 282                        else
 283                                suffix = "SSP";
 284                } else {
 285                        if (fus_dat2.cn56xx.nocrypto)
 286                                suffix = "CP";
 287                        else {
 288                                suffix = "NSP";
 289                                if (fus_dat3.s.nozip)
 290                                        suffix = "SCP";
 291
 292                                if (fus_dat3.s.bar2_en)
 293                                        suffix = "NSPB2";
 294                        }
 295                        if (fus3.cn56xx.crip_1024k)
 296                                family = "54";
 297                        else
 298                                family = "56";
 299                }
 300                break;
 301        case 6:         /* CN50XX */
 302                family = "50";
 303                break;
 304        case 7:         /* CN52XX */
 305                if (fus3.cn52xx.crip_256k)
 306                        family = "51";
 307                else
 308                        family = "52";
 309                break;
 310        case 0x93:              /* CN61XX */
 311                family = "61";
 312                if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto)
 313                        suffix = "AP";
 314                if (fus_dat2.cn61xx.nocrypto)
 315                        suffix = "CP";
 316                else if (fus_dat2.cn61xx.dorm_crypto)
 317                        suffix = "DAP";
 318                else if (fus_dat3.cn61xx.nozip)
 319                        suffix = "SCP";
 320                break;
 321        case 0x90:              /* CN63XX */
 322                family = "63";
 323                if (fus_dat3.s.l2c_crip == 2)
 324                        family = "62";
 325                if (num_cores == 6)     /* Other core counts match generic */
 326                        core_model = "35";
 327                if (fus_dat2.cn63xx.nocrypto)
 328                        suffix = "CP";
 329                else if (fus_dat2.cn63xx.dorm_crypto)
 330                        suffix = "DAP";
 331                else if (fus_dat3.cn63xx.nozip)
 332                        suffix = "SCP";
 333                else
 334                        suffix = "AAP";
 335                break;
 336        case 0x92:              /* CN66XX */
 337                family = "66";
 338                if (num_cores == 6)     /* Other core counts match generic */
 339                        core_model = "35";
 340                if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto)
 341                        suffix = "AP";
 342                if (fus_dat2.cn66xx.nocrypto)
 343                        suffix = "CP";
 344                else if (fus_dat2.cn66xx.dorm_crypto)
 345                        suffix = "DAP";
 346                else if (fus_dat3.cn66xx.nozip)
 347                        suffix = "SCP";
 348                else
 349                        suffix = "AAP";
 350                break;
 351        case 0x91:              /* CN68XX */
 352                family = "68";
 353                if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip)
 354                        suffix = "CP";
 355                else if (fus_dat2.cn68xx.dorm_crypto)
 356                        suffix = "DAP";
 357                else if (fus_dat3.cn68xx.nozip)
 358                        suffix = "SCP";
 359                else if (fus_dat2.cn68xx.nocrypto)
 360                        suffix = "SP";
 361                else
 362                        suffix = "AAP";
 363                break;
 364        default:
 365                family = "XX";
 366                core_model = "XX";
 367                strcpy(pass, "X.X");
 368                suffix = "XXX";
 369                break;
 370        }
 371
 372        clock_mhz = octeon_get_clock_rate() / 1000000;
 373        if (family[0] != '3') {
 374                int fuse_base = 384 / 8;
 375                if (family[0] == '6')
 376                        fuse_base = 832 / 8;
 377
 378                /* Check for model in fuses, overrides normal decode */
 379                /* This is _not_ valid for Octeon CN3XXX models */
 380                fuse_data |= cvmx_fuse_read_byte(fuse_base + 3);
 381                fuse_data = fuse_data << 8;
 382                fuse_data |= cvmx_fuse_read_byte(fuse_base + 2);
 383                fuse_data = fuse_data << 8;
 384                fuse_data |= cvmx_fuse_read_byte(fuse_base + 1);
 385                fuse_data = fuse_data << 8;
 386                fuse_data |= cvmx_fuse_read_byte(fuse_base);
 387                if (fuse_data & 0x7ffff) {
 388                        int model = fuse_data & 0x3fff;
 389                        int suffix = (fuse_data >> 14) & 0x1f;
 390                        if (suffix && model) {
 391                                /* Have both number and suffix in fuses, so both */
 392                                sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1);
 393                                core_model = "";
 394                                family = fuse_model;
 395                        } else if (suffix && !model) {
 396                                /* Only have suffix, so add suffix to 'normal' model number */
 397                                sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1);
 398                                core_model = fuse_model;
 399                        } else {
 400                                /* Don't have suffix, so just use model from fuses */
 401                                sprintf(fuse_model, "%d", model);
 402                                core_model = "";
 403                                family = fuse_model;
 404                        }
 405                }
 406        }
 407        sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix);
 408        return buffer;
 409}
 410