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 */ 43 const 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 */ 54 const 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