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