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