ivm.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2011
  4. * Holger Brunck, Keymile GmbH Hannover, holger.brunck@keymile.com
  5. */
  6. #include <common.h>
  7. #include <cli_hush.h>
  8. #include <env.h>
  9. #include <i2c.h>
  10. #include "common.h"
  11. #define MAC_STR_SZ 20
  12. static int ivm_calc_crc(unsigned char *buf, int len)
  13. {
  14. const unsigned short crc_tab[16] = {
  15. 0x0000, 0xCC01, 0xD801, 0x1400,
  16. 0xF001, 0x3C00, 0x2800, 0xE401,
  17. 0xA001, 0x6C00, 0x7800, 0xB401,
  18. 0x5000, 0x9C01, 0x8801, 0x4400};
  19. unsigned short crc = 0; /* final result */
  20. unsigned short r1 = 0; /* temp */
  21. unsigned char byte = 0; /* input buffer */
  22. int i;
  23. /* calculate CRC from array data */
  24. for (i = 0; i < len; i++) {
  25. byte = buf[i];
  26. /* lower 4 bits */
  27. r1 = crc_tab[crc & 0xF];
  28. crc = ((crc) >> 4) & 0x0FFF;
  29. crc = crc ^ r1 ^ crc_tab[byte & 0xF];
  30. /* upper 4 bits */
  31. r1 = crc_tab[crc & 0xF];
  32. crc = (crc >> 4) & 0x0FFF;
  33. crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF];
  34. }
  35. return crc;
  36. }
  37. static int ivm_set_value(char *name, char *value)
  38. {
  39. char tempbuf[256];
  40. if (value != NULL) {
  41. sprintf(tempbuf, "%s=%s", name, value);
  42. return set_local_var(tempbuf, 0);
  43. } else {
  44. unset_local_var(name);
  45. }
  46. return 0;
  47. }
  48. static int ivm_get_value(unsigned char *buf, int len, char *name, int off,
  49. int check)
  50. {
  51. unsigned short val;
  52. unsigned char valbuf[30];
  53. if ((buf[off + 0] != buf[off + 2]) &&
  54. (buf[off + 2] != buf[off + 4])) {
  55. printf("%s Error corrupted %s\n", __func__, name);
  56. val = -1;
  57. } else {
  58. val = buf[off + 0] + (buf[off + 1] << 8);
  59. if ((val == 0) && (check == 1))
  60. val = -1;
  61. }
  62. sprintf((char *)valbuf, "%x", val);
  63. ivm_set_value(name, (char *)valbuf);
  64. return val;
  65. }
  66. #define INV_BLOCKSIZE 0x100
  67. #define INV_DATAADDRESS 0x21
  68. #define INVENTORYDATASIZE (INV_BLOCKSIZE - INV_DATAADDRESS - 3)
  69. #define IVM_POS_SHORT_TEXT 0
  70. #define IVM_POS_MANU_ID 1
  71. #define IVM_POS_MANU_SERIAL 2
  72. #define IVM_POS_PART_NUMBER 3
  73. #define IVM_POS_BUILD_STATE 4
  74. #define IVM_POS_SUPPLIER_PART_NUMBER 5
  75. #define IVM_POS_DELIVERY_DATE 6
  76. #define IVM_POS_SUPPLIER_BUILD_STATE 7
  77. #define IVM_POS_CUSTOMER_ID 8
  78. #define IVM_POS_CUSTOMER_PROD_ID 9
  79. #define IVM_POS_HISTORY 10
  80. #define IVM_POS_SYMBOL_ONLY 11
  81. static char convert_char(char c)
  82. {
  83. return (c < ' ' || c > '~') ? '.' : c;
  84. }
  85. static int ivm_findinventorystring(int type,
  86. unsigned char *const string,
  87. unsigned long maxlen,
  88. unsigned char *buf)
  89. {
  90. int xcode = 0;
  91. unsigned long cr = 0;
  92. unsigned long addr = INV_DATAADDRESS;
  93. unsigned long size = 0;
  94. unsigned long nr = type;
  95. int stop = 0; /* stop on semicolon */
  96. memset(string, '\0', maxlen);
  97. switch (type) {
  98. case IVM_POS_SYMBOL_ONLY:
  99. nr = 0;
  100. stop = 1;
  101. break;
  102. default:
  103. nr = type;
  104. stop = 0;
  105. }
  106. /* Look for the requested number of CR. */
  107. while ((cr != nr) && (addr < INVENTORYDATASIZE)) {
  108. if (buf[addr] == '\r')
  109. cr++;
  110. addr++;
  111. }
  112. /*
  113. * the expected number of CR was found until the end of the IVM
  114. * content --> fill string
  115. */
  116. if (addr < INVENTORYDATASIZE) {
  117. /* Copy the IVM string in the corresponding string */
  118. for (; (buf[addr] != '\r') &&
  119. ((buf[addr] != ';') || (!stop)) &&
  120. (size < (maxlen - 1) &&
  121. (addr < INVENTORYDATASIZE)); addr++) {
  122. size += sprintf((char *)string + size, "%c",
  123. convert_char (buf[addr]));
  124. }
  125. /*
  126. * copy phase is done: check if everything is ok. If not,
  127. * the inventory data is most probably corrupted: tell
  128. * the world there is a problem!
  129. */
  130. if (addr == INVENTORYDATASIZE) {
  131. xcode = -1;
  132. printf("Error end of string not found\n");
  133. } else if ((size > (maxlen - 1)) &&
  134. (buf[addr] != '\r')) {
  135. xcode = -1;
  136. printf("string too long till next CR\n");
  137. }
  138. } else {
  139. /*
  140. * some CR are missing...
  141. * the inventory data is most probably corrupted
  142. */
  143. xcode = -1;
  144. printf("not enough cr found\n");
  145. }
  146. return xcode;
  147. }
  148. #define GET_STRING(name, which, len) \
  149. if (ivm_findinventorystring(which, valbuf, len, buf) == 0) { \
  150. ivm_set_value(name, (char *)valbuf); \
  151. }
  152. static int ivm_check_crc(unsigned char *buf, int block)
  153. {
  154. unsigned long crc;
  155. unsigned long crceeprom;
  156. crc = ivm_calc_crc(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2);
  157. crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \
  158. buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256);
  159. if (crc != crceeprom) {
  160. if (block == 0)
  161. printf("Error CRC Block: %d EEprom: calculated: \
  162. %lx EEprom: %lx\n", block, crc, crceeprom);
  163. return -1;
  164. }
  165. return 0;
  166. }
  167. /* take care of the possible MAC address offset and the IVM content offset */
  168. static int process_mac(unsigned char *valbuf, unsigned char *buf,
  169. int offset, bool unique)
  170. {
  171. unsigned char mac[6];
  172. unsigned long val = (buf[4] << 16) + (buf[5] << 8) + buf[6];
  173. /* use an intermediate buffer, to not change IVM content
  174. * MAC address is at offset 1
  175. */
  176. memcpy(mac, buf+1, 6);
  177. /* MAC adress can be set to locally administred, this is only allowed
  178. * for interfaces which have now connection to the outside. For these
  179. * addresses we need to set the second bit in the first byte.
  180. */
  181. if (!unique)
  182. mac[0] |= 0x2;
  183. if (offset) {
  184. val += offset;
  185. mac[3] = (val >> 16) & 0xff;
  186. mac[4] = (val >> 8) & 0xff;
  187. mac[5] = val & 0xff;
  188. }
  189. sprintf((char *)valbuf, "%pM", mac);
  190. return 0;
  191. }
  192. static int ivm_analyze_block2(unsigned char *buf, int len)
  193. {
  194. unsigned char valbuf[MAC_STR_SZ];
  195. unsigned long count;
  196. /* IVM_MAC Adress begins at offset 1 */
  197. sprintf((char *)valbuf, "%pM", buf + 1);
  198. ivm_set_value("IVM_MacAddress", (char *)valbuf);
  199. /* IVM_MacCount */
  200. count = (buf[10] << 24) +
  201. (buf[11] << 16) +
  202. (buf[12] << 8) +
  203. buf[13];
  204. if (count == 0xffffffff)
  205. count = 1;
  206. sprintf((char *)valbuf, "%lx", count);
  207. ivm_set_value("IVM_MacCount", (char *)valbuf);
  208. return 0;
  209. }
  210. int ivm_analyze_eeprom(unsigned char *buf, int len)
  211. {
  212. unsigned short val;
  213. unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN];
  214. unsigned char *tmp;
  215. if (ivm_check_crc(buf, 0) != 0)
  216. return -1;
  217. ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
  218. "IVM_BoardId", 0, 1);
  219. val = ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
  220. "IVM_HWKey", 6, 1);
  221. if (val != 0xffff) {
  222. sprintf((char *)valbuf, "%x", ((val / 100) % 10));
  223. ivm_set_value("IVM_HWVariant", (char *)valbuf);
  224. sprintf((char *)valbuf, "%x", (val % 100));
  225. ivm_set_value("IVM_HWVersion", (char *)valbuf);
  226. }
  227. ivm_get_value(buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN,
  228. "IVM_Functions", 12, 0);
  229. GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8)
  230. GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64)
  231. tmp = (unsigned char *)env_get("IVM_DeviceName");
  232. if (tmp) {
  233. int len = strlen((char *)tmp);
  234. int i = 0;
  235. while (i < len) {
  236. if (tmp[i] == ';') {
  237. ivm_set_value("IVM_ShortText",
  238. (char *)&tmp[i + 1]);
  239. break;
  240. }
  241. i++;
  242. }
  243. if (i >= len)
  244. ivm_set_value("IVM_ShortText", NULL);
  245. } else {
  246. ivm_set_value("IVM_ShortText", NULL);
  247. }
  248. GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32)
  249. GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20)
  250. GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32)
  251. GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32)
  252. GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32)
  253. GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32)
  254. GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32)
  255. GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32)
  256. GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32)
  257. if (ivm_check_crc(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0)
  258. return 0;
  259. ivm_analyze_block2(&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2],
  260. CONFIG_SYS_IVM_EEPROM_PAGE_LEN);
  261. return 0;
  262. }
  263. static int ivm_populate_env(unsigned char *buf, int len)
  264. {
  265. unsigned char *page2;
  266. unsigned char valbuf[MAC_STR_SZ];
  267. /* do we have the page 2 filled ? if not return */
  268. if (ivm_check_crc(buf, 2))
  269. return 0;
  270. page2 = &buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN*2];
  271. #ifndef CONFIG_KMTEGR1
  272. /* if an offset is defined, add it */
  273. process_mac(valbuf, page2, CONFIG_PIGGY_MAC_ADRESS_OFFSET, true);
  274. env_set((char *)"ethaddr", (char *)valbuf);
  275. #ifdef CONFIG_KMVECT1
  276. /* KMVECT1 has two ethernet interfaces */
  277. process_mac(valbuf, page2, 1, true);
  278. env_set((char *)"eth1addr", (char *)valbuf);
  279. #endif
  280. #else
  281. /* KMTEGR1 has a special setup. eth0 has no connection to the outside and
  282. * gets an locally administred MAC address, eth1 is the debug interface and
  283. * gets the official MAC address from the IVM
  284. */
  285. process_mac(valbuf, page2, CONFIG_PIGGY_MAC_ADRESS_OFFSET, false);
  286. env_set((char *)"ethaddr", (char *)valbuf);
  287. process_mac(valbuf, page2, CONFIG_PIGGY_MAC_ADRESS_OFFSET, true);
  288. env_set((char *)"eth1addr", (char *)valbuf);
  289. #endif
  290. return 0;
  291. }
  292. int ivm_read_eeprom(unsigned char *buf, int len)
  293. {
  294. int ret;
  295. i2c_set_bus_num(CONFIG_KM_IVM_BUS);
  296. /* add deblocking here */
  297. i2c_make_abort();
  298. ret = i2c_read(CONFIG_SYS_IVM_EEPROM_ADR, 0, 1, buf, len);
  299. if (ret != 0) {
  300. printf("Error reading EEprom\n");
  301. return -2;
  302. }
  303. return ivm_populate_env(buf, len);
  304. }