octeon-model.c 9.3 KB

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