cros_ec.c 10 KB

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