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