eeprom.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2014 Gateworks Corporation
  4. * Author: Tim Harvey <tharvey@gateworks.com>
  5. */
  6. #include <common.h>
  7. #include <command.h>
  8. #include <errno.h>
  9. #include <hexdump.h>
  10. #include <i2c.h>
  11. #include <log.h>
  12. #include <malloc.h>
  13. #include <asm/bitops.h>
  14. #include <linux/delay.h>
  15. #include "gsc.h"
  16. #include "ventana_eeprom.h"
  17. /* read ventana EEPROM, check for validity, and return baseboard type */
  18. int
  19. read_eeprom(int bus, struct ventana_board_info *info)
  20. {
  21. int i;
  22. int chksum;
  23. char baseboard;
  24. int type;
  25. unsigned char *buf = (unsigned char *)info;
  26. memset(info, 0, sizeof(*info));
  27. /*
  28. * On a board with a missing/depleted backup battery for GSC, the
  29. * board may be ready to probe the GSC before its firmware is
  30. * running. We will wait here indefinately for the GSC/EEPROM.
  31. */
  32. while (1) {
  33. if (0 == i2c_set_bus_num(bus) &&
  34. 0 == i2c_probe(GSC_EEPROM_ADDR))
  35. break;
  36. mdelay(1);
  37. }
  38. /* read eeprom config section */
  39. if (gsc_i2c_read(GSC_EEPROM_ADDR, 0x00, 1, buf, sizeof(*info))) {
  40. puts("EEPROM: Failed to read EEPROM\n");
  41. return GW_UNKNOWN;
  42. }
  43. /* sanity checks */
  44. if (info->model[0] != 'G' || info->model[1] != 'W') {
  45. puts("EEPROM: Invalid Model in EEPROM\n");
  46. print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf,
  47. sizeof(*info));
  48. return GW_UNKNOWN;
  49. }
  50. /* validate checksum */
  51. for (chksum = 0, i = 0; i < sizeof(*info)-2; i++)
  52. chksum += buf[i];
  53. if ((info->chksum[0] != chksum>>8) ||
  54. (info->chksum[1] != (chksum&0xff))) {
  55. puts("EEPROM: Failed EEPROM checksum\n");
  56. print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf,
  57. sizeof(*info));
  58. return GW_UNKNOWN;
  59. }
  60. /* original GW5400-A prototype */
  61. baseboard = info->model[3];
  62. if (strncasecmp((const char *)info->model, "GW5400-A", 8) == 0)
  63. baseboard = '0';
  64. type = GW_UNKNOWN;
  65. switch (baseboard) {
  66. case '0': /* original GW5400-A prototype */
  67. type = GW54proto;
  68. break;
  69. case '1':
  70. type = GW51xx;
  71. break;
  72. case '2':
  73. type = GW52xx;
  74. break;
  75. case '3':
  76. type = GW53xx;
  77. break;
  78. case '4':
  79. type = GW54xx;
  80. break;
  81. case '5':
  82. if (info->model[4] == '1') {
  83. type = GW551x;
  84. break;
  85. } else if (info->model[4] == '2') {
  86. type = GW552x;
  87. break;
  88. } else if (info->model[4] == '3') {
  89. type = GW553x;
  90. break;
  91. }
  92. break;
  93. case '6':
  94. if (info->model[4] == '0')
  95. type = GW560x;
  96. break;
  97. case '9':
  98. if (info->model[4] == '0' && info->model[5] == '1')
  99. type = GW5901;
  100. else if (info->model[4] == '0' && info->model[5] == '2')
  101. type = GW5902;
  102. else if (info->model[4] == '0' && info->model[5] == '3')
  103. type = GW5903;
  104. else if (info->model[4] == '0' && info->model[5] == '4')
  105. type = GW5904;
  106. else if (info->model[4] == '0' && info->model[5] == '5')
  107. type = GW5905;
  108. else if (info->model[4] == '0' && info->model[5] == '6')
  109. type = GW5906;
  110. else if (info->model[4] == '0' && info->model[5] == '7')
  111. type = GW5907;
  112. else if (info->model[4] == '0' && info->model[5] == '8')
  113. type = GW5908;
  114. else if (info->model[4] == '0' && info->model[5] == '9')
  115. type = GW5909;
  116. break;
  117. default:
  118. printf("EEPROM: Unknown model in EEPROM: %s\n", info->model);
  119. print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf,
  120. sizeof(*info));
  121. break;
  122. }
  123. return type;
  124. }
  125. /* list of config bits that the bootloader will remove from dtb if not set */
  126. struct ventana_eeprom_config econfig[] = {
  127. { "eth0", "ethernet0", EECONFIG_ETH0 },
  128. { "usb0", NULL, EECONFIG_USB0 },
  129. { "usb1", NULL, EECONFIG_USB1 },
  130. { "mmc0", NULL, EECONFIG_SD0 },
  131. { "mmc1", NULL, EECONFIG_SD1 },
  132. { "mmc2", NULL, EECONFIG_SD2 },
  133. { "mmc3", NULL, EECONFIG_SD3 },
  134. { /* Sentinel */ }
  135. };
  136. #if defined(CONFIG_CMD_EECONFIG) && !defined(CONFIG_SPL_BUILD)
  137. static struct ventana_eeprom_config *get_config(const char *name)
  138. {
  139. struct ventana_eeprom_config *cfg = econfig;
  140. while (cfg->name) {
  141. if (0 == strcmp(name, cfg->name))
  142. return cfg;
  143. cfg++;
  144. }
  145. return NULL;
  146. }
  147. static u8 econfig_bytes[sizeof(ventana_info.config)];
  148. static int econfig_init = -1;
  149. static int do_econfig(struct cmd_tbl *cmdtp, int flag, int argc,
  150. char *const argv[])
  151. {
  152. struct ventana_eeprom_config *cfg;
  153. struct ventana_board_info *info = &ventana_info;
  154. int i;
  155. if (argc < 2)
  156. return CMD_RET_USAGE;
  157. /* initialize */
  158. if (econfig_init != 1) {
  159. memcpy(econfig_bytes, info->config, sizeof(econfig_bytes));
  160. econfig_init = 1;
  161. }
  162. /* list configs */
  163. if ((strncmp(argv[1], "list", 4) == 0)) {
  164. cfg = econfig;
  165. while (cfg->name) {
  166. printf("%s: %d\n", cfg->name,
  167. test_bit(cfg->bit, econfig_bytes) ? 1 : 0);
  168. cfg++;
  169. }
  170. }
  171. /* save */
  172. else if ((strncmp(argv[1], "save", 4) == 0)) {
  173. unsigned char *buf = (unsigned char *)info;
  174. int chksum;
  175. /* calculate new checksum */
  176. memcpy(info->config, econfig_bytes, sizeof(econfig_bytes));
  177. for (chksum = 0, i = 0; i < sizeof(*info)-2; i++)
  178. chksum += buf[i];
  179. debug("old chksum:0x%04x\n",
  180. (info->chksum[0] << 8) | info->chksum[1]);
  181. debug("new chksum:0x%04x\n", chksum);
  182. info->chksum[0] = chksum >> 8;
  183. info->chksum[1] = chksum & 0xff;
  184. /* write new config data */
  185. if (gsc_i2c_write(GSC_EEPROM_ADDR, info->config - (u8 *)info,
  186. 1, econfig_bytes, sizeof(econfig_bytes))) {
  187. printf("EEPROM: Failed updating config\n");
  188. return CMD_RET_FAILURE;
  189. }
  190. /* write new config data */
  191. if (gsc_i2c_write(GSC_EEPROM_ADDR, info->chksum - (u8 *)info,
  192. 1, info->chksum, 2)) {
  193. printf("EEPROM: Failed updating checksum\n");
  194. return CMD_RET_FAILURE;
  195. }
  196. printf("Config saved to EEPROM\n");
  197. }
  198. /* get config */
  199. else if (argc == 2) {
  200. cfg = get_config(argv[1]);
  201. if (cfg) {
  202. printf("%s: %d\n", cfg->name,
  203. test_bit(cfg->bit, econfig_bytes) ? 1 : 0);
  204. } else {
  205. printf("invalid config: %s\n", argv[1]);
  206. return CMD_RET_FAILURE;
  207. }
  208. }
  209. /* set config */
  210. else if (argc == 3) {
  211. cfg = get_config(argv[1]);
  212. if (cfg) {
  213. if (simple_strtol(argv[2], NULL, 10)) {
  214. test_and_set_bit(cfg->bit, econfig_bytes);
  215. printf("Enabled %s\n", cfg->name);
  216. } else {
  217. test_and_clear_bit(cfg->bit, econfig_bytes);
  218. printf("Disabled %s\n", cfg->name);
  219. }
  220. } else {
  221. printf("invalid config: %s\n", argv[1]);
  222. return CMD_RET_FAILURE;
  223. }
  224. }
  225. else
  226. return CMD_RET_USAGE;
  227. return CMD_RET_SUCCESS;
  228. }
  229. U_BOOT_CMD(
  230. econfig, 3, 0, do_econfig,
  231. "EEPROM configuration",
  232. "list - list config\n"
  233. "save - save config to EEPROM\n"
  234. "<name> - get config 'name'\n"
  235. "<name> [0|1] - set config 'name' to value\n"
  236. );
  237. #endif /* CONFIG_CMD_EECONFIG */