ivm.c 9.4 KB

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