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