cros_ec.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. * Chromium OS cros_ec driver
  3. *
  4. * Copyright (c) 2016 The Chromium OS Authors.
  5. * Copyright (c) 2016 National Instruments Corp
  6. *
  7. * SPDX-License-Identifier: GPL-2.0+
  8. */
  9. #include <common.h>
  10. #include <command.h>
  11. #include <cros_ec.h>
  12. #include <dm.h>
  13. #include <dm/device-internal.h>
  14. #include <dm/uclass-internal.h>
  15. /* Note: depends on enum ec_current_image */
  16. static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
  17. DECLARE_GLOBAL_DATA_PTR;
  18. /**
  19. * Decode a flash region parameter
  20. *
  21. * @param argc Number of params remaining
  22. * @param argv List of remaining parameters
  23. * @return flash region (EC_FLASH_REGION_...) or -1 on error
  24. */
  25. static int cros_ec_decode_region(int argc, char * const argv[])
  26. {
  27. if (argc > 0) {
  28. if (0 == strcmp(*argv, "rw"))
  29. return EC_FLASH_REGION_RW;
  30. else if (0 == strcmp(*argv, "ro"))
  31. return EC_FLASH_REGION_RO;
  32. debug("%s: Invalid region '%s'\n", __func__, *argv);
  33. } else {
  34. debug("%s: Missing region parameter\n", __func__);
  35. }
  36. return -1;
  37. }
  38. /**
  39. * Perform a flash read or write command
  40. *
  41. * @param dev CROS-EC device to read/write
  42. * @param is_write 1 do to a write, 0 to do a read
  43. * @param argc Number of arguments
  44. * @param argv Arguments (2 is region, 3 is address)
  45. * @return 0 for ok, 1 for a usage error or -ve for ec command error
  46. * (negative EC_RES_...)
  47. */
  48. static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
  49. char * const argv[])
  50. {
  51. uint32_t offset, size = -1U, region_size;
  52. unsigned long addr;
  53. char *endp;
  54. int region;
  55. int ret;
  56. region = cros_ec_decode_region(argc - 2, argv + 2);
  57. if (region == -1)
  58. return 1;
  59. if (argc < 4)
  60. return 1;
  61. addr = simple_strtoul(argv[3], &endp, 16);
  62. if (*argv[3] == 0 || *endp != 0)
  63. return 1;
  64. if (argc > 4) {
  65. size = simple_strtoul(argv[4], &endp, 16);
  66. if (*argv[4] == 0 || *endp != 0)
  67. return 1;
  68. }
  69. ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
  70. if (ret) {
  71. debug("%s: Could not read region info\n", __func__);
  72. return ret;
  73. }
  74. if (size == -1U)
  75. size = region_size;
  76. ret = is_write ?
  77. cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
  78. cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
  79. if (ret) {
  80. debug("%s: Could not %s region\n", __func__,
  81. is_write ? "write" : "read");
  82. return ret;
  83. }
  84. return 0;
  85. }
  86. static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  87. {
  88. struct cros_ec_dev *dev;
  89. struct udevice *udev;
  90. const char *cmd;
  91. int ret = 0;
  92. if (argc < 2)
  93. return CMD_RET_USAGE;
  94. cmd = argv[1];
  95. if (0 == strcmp("init", cmd)) {
  96. /* Remove any existing device */
  97. ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
  98. if (!ret)
  99. device_remove(udev);
  100. ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
  101. if (ret) {
  102. printf("Could not init cros_ec device (err %d)\n", ret);
  103. return 1;
  104. }
  105. return 0;
  106. }
  107. ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
  108. if (ret) {
  109. printf("Cannot get cros-ec device (err=%d)\n", ret);
  110. return 1;
  111. }
  112. dev = dev_get_uclass_priv(udev);
  113. if (0 == strcmp("id", cmd)) {
  114. char id[MSG_BYTES];
  115. if (cros_ec_read_id(dev, id, sizeof(id))) {
  116. debug("%s: Could not read KBC ID\n", __func__);
  117. return 1;
  118. }
  119. printf("%s\n", id);
  120. } else if (0 == strcmp("info", cmd)) {
  121. struct ec_response_mkbp_info info;
  122. if (cros_ec_info(dev, &info)) {
  123. debug("%s: Could not read KBC info\n", __func__);
  124. return 1;
  125. }
  126. printf("rows = %u\n", info.rows);
  127. printf("cols = %u\n", info.cols);
  128. printf("switches = %#x\n", info.switches);
  129. } else if (0 == strcmp("curimage", cmd)) {
  130. enum ec_current_image image;
  131. if (cros_ec_read_current_image(dev, &image)) {
  132. debug("%s: Could not read KBC image\n", __func__);
  133. return 1;
  134. }
  135. printf("%d\n", image);
  136. } else if (0 == strcmp("hash", cmd)) {
  137. struct ec_response_vboot_hash hash;
  138. int i;
  139. if (cros_ec_read_hash(dev, &hash)) {
  140. debug("%s: Could not read KBC hash\n", __func__);
  141. return 1;
  142. }
  143. if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
  144. printf("type: SHA-256\n");
  145. else
  146. printf("type: %d\n", hash.hash_type);
  147. printf("offset: 0x%08x\n", hash.offset);
  148. printf("size: 0x%08x\n", hash.size);
  149. printf("digest: ");
  150. for (i = 0; i < hash.digest_size; i++)
  151. printf("%02x", hash.hash_digest[i]);
  152. printf("\n");
  153. } else if (0 == strcmp("reboot", cmd)) {
  154. int region;
  155. enum ec_reboot_cmd cmd;
  156. if (argc >= 3 && !strcmp(argv[2], "cold")) {
  157. cmd = EC_REBOOT_COLD;
  158. } else {
  159. region = cros_ec_decode_region(argc - 2, argv + 2);
  160. if (region == EC_FLASH_REGION_RO)
  161. cmd = EC_REBOOT_JUMP_RO;
  162. else if (region == EC_FLASH_REGION_RW)
  163. cmd = EC_REBOOT_JUMP_RW;
  164. else
  165. return CMD_RET_USAGE;
  166. }
  167. if (cros_ec_reboot(dev, cmd, 0)) {
  168. debug("%s: Could not reboot KBC\n", __func__);
  169. return 1;
  170. }
  171. } else if (0 == strcmp("events", cmd)) {
  172. uint32_t events;
  173. if (cros_ec_get_host_events(dev, &events)) {
  174. debug("%s: Could not read host events\n", __func__);
  175. return 1;
  176. }
  177. printf("0x%08x\n", events);
  178. } else if (0 == strcmp("clrevents", cmd)) {
  179. uint32_t events = 0x7fffffff;
  180. if (argc >= 3)
  181. events = simple_strtol(argv[2], NULL, 0);
  182. if (cros_ec_clear_host_events(dev, events)) {
  183. debug("%s: Could not clear host events\n", __func__);
  184. return 1;
  185. }
  186. } else if (0 == strcmp("read", cmd)) {
  187. ret = do_read_write(dev, 0, argc, argv);
  188. if (ret > 0)
  189. return CMD_RET_USAGE;
  190. } else if (0 == strcmp("write", cmd)) {
  191. ret = do_read_write(dev, 1, argc, argv);
  192. if (ret > 0)
  193. return CMD_RET_USAGE;
  194. } else if (0 == strcmp("erase", cmd)) {
  195. int region = cros_ec_decode_region(argc - 2, argv + 2);
  196. uint32_t offset, size;
  197. if (region == -1)
  198. return CMD_RET_USAGE;
  199. if (cros_ec_flash_offset(dev, region, &offset, &size)) {
  200. debug("%s: Could not read region info\n", __func__);
  201. ret = -1;
  202. } else {
  203. ret = cros_ec_flash_erase(dev, offset, size);
  204. if (ret) {
  205. debug("%s: Could not erase region\n",
  206. __func__);
  207. }
  208. }
  209. } else if (0 == strcmp("regioninfo", cmd)) {
  210. int region = cros_ec_decode_region(argc - 2, argv + 2);
  211. uint32_t offset, size;
  212. if (region == -1)
  213. return CMD_RET_USAGE;
  214. ret = cros_ec_flash_offset(dev, region, &offset, &size);
  215. if (ret) {
  216. debug("%s: Could not read region info\n", __func__);
  217. } else {
  218. printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
  219. "RO" : "RW");
  220. printf("Offset: %x\n", offset);
  221. printf("Size: %x\n", size);
  222. }
  223. } else if (0 == strcmp("flashinfo", cmd)) {
  224. struct ec_response_flash_info p;
  225. ret = cros_ec_read_flashinfo(dev, &p);
  226. if (!ret) {
  227. printf("Flash size: %u\n", p.flash_size);
  228. printf("Write block size: %u\n", p.write_block_size);
  229. printf("Erase block size: %u\n", p.erase_block_size);
  230. }
  231. } else if (0 == strcmp("vbnvcontext", cmd)) {
  232. uint8_t block[EC_VBNV_BLOCK_SIZE];
  233. char buf[3];
  234. int i, len;
  235. unsigned long result;
  236. if (argc <= 2) {
  237. ret = cros_ec_read_vbnvcontext(dev, block);
  238. if (!ret) {
  239. printf("vbnv_block: ");
  240. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
  241. printf("%02x", block[i]);
  242. putc('\n');
  243. }
  244. } else {
  245. /*
  246. * TODO(clchiou): Move this to a utility function as
  247. * cmd_spi might want to call it.
  248. */
  249. memset(block, 0, EC_VBNV_BLOCK_SIZE);
  250. len = strlen(argv[2]);
  251. buf[2] = '\0';
  252. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
  253. if (i * 2 >= len)
  254. break;
  255. buf[0] = argv[2][i * 2];
  256. if (i * 2 + 1 >= len)
  257. buf[1] = '0';
  258. else
  259. buf[1] = argv[2][i * 2 + 1];
  260. strict_strtoul(buf, 16, &result);
  261. block[i] = result;
  262. }
  263. ret = cros_ec_write_vbnvcontext(dev, block);
  264. }
  265. if (ret) {
  266. debug("%s: Could not %s VbNvContext\n", __func__,
  267. argc <= 2 ? "read" : "write");
  268. }
  269. } else if (0 == strcmp("test", cmd)) {
  270. int result = cros_ec_test(dev);
  271. if (result)
  272. printf("Test failed with error %d\n", result);
  273. else
  274. puts("Test passed\n");
  275. } else if (0 == strcmp("version", cmd)) {
  276. struct ec_response_get_version *p;
  277. char *build_string;
  278. ret = cros_ec_read_version(dev, &p);
  279. if (!ret) {
  280. /* Print versions */
  281. printf("RO version: %1.*s\n",
  282. (int)sizeof(p->version_string_ro),
  283. p->version_string_ro);
  284. printf("RW version: %1.*s\n",
  285. (int)sizeof(p->version_string_rw),
  286. p->version_string_rw);
  287. printf("Firmware copy: %s\n",
  288. (p->current_image <
  289. ARRAY_SIZE(ec_current_image_name) ?
  290. ec_current_image_name[p->current_image] :
  291. "?"));
  292. ret = cros_ec_read_build_info(dev, &build_string);
  293. if (!ret)
  294. printf("Build info: %s\n", build_string);
  295. }
  296. } else if (0 == strcmp("ldo", cmd)) {
  297. uint8_t index, state;
  298. char *endp;
  299. if (argc < 3)
  300. return CMD_RET_USAGE;
  301. index = simple_strtoul(argv[2], &endp, 10);
  302. if (*argv[2] == 0 || *endp != 0)
  303. return CMD_RET_USAGE;
  304. if (argc > 3) {
  305. state = simple_strtoul(argv[3], &endp, 10);
  306. if (*argv[3] == 0 || *endp != 0)
  307. return CMD_RET_USAGE;
  308. ret = cros_ec_set_ldo(udev, index, state);
  309. } else {
  310. ret = cros_ec_get_ldo(udev, index, &state);
  311. if (!ret) {
  312. printf("LDO%d: %s\n", index,
  313. state == EC_LDO_STATE_ON ?
  314. "on" : "off");
  315. }
  316. }
  317. if (ret) {
  318. debug("%s: Could not access LDO%d\n", __func__, index);
  319. return ret;
  320. }
  321. } else {
  322. return CMD_RET_USAGE;
  323. }
  324. if (ret < 0) {
  325. printf("Error: CROS-EC command failed (error %d)\n", ret);
  326. ret = 1;
  327. }
  328. return ret;
  329. }
  330. U_BOOT_CMD(
  331. crosec, 6, 1, do_cros_ec,
  332. "CROS-EC utility command",
  333. "init Re-init CROS-EC (done on startup automatically)\n"
  334. "crosec id Read CROS-EC ID\n"
  335. "crosec info Read CROS-EC info\n"
  336. "crosec curimage Read CROS-EC current image\n"
  337. "crosec hash Read CROS-EC hash\n"
  338. "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
  339. "crosec events Read CROS-EC host events\n"
  340. "crosec clrevents [mask] Clear CROS-EC host events\n"
  341. "crosec regioninfo <ro|rw> Read image info\n"
  342. "crosec flashinfo Read flash info\n"
  343. "crosec erase <ro|rw> Erase EC image\n"
  344. "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
  345. "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
  346. "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
  347. "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
  348. "crosec test run tests on cros_ec\n"
  349. "crosec version Read CROS-EC version"
  350. );