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 */ 47 const 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 */ 58 const 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