cros_ec.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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_ACTIVE;
  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 udevice *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 udevice *dev;
  87. const char *cmd;
  88. int ret = 0;
  89. if (argc < 2)
  90. return CMD_RET_USAGE;
  91. cmd = argv[1];
  92. if (0 == strcmp("init", cmd)) {
  93. /* Remove any existing device */
  94. ret = uclass_find_device(UCLASS_CROS_EC, 0, &dev);
  95. if (!ret)
  96. device_remove(dev, DM_REMOVE_NORMAL);
  97. ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
  98. if (ret) {
  99. printf("Could not init cros_ec device (err %d)\n", ret);
  100. return 1;
  101. }
  102. return 0;
  103. }
  104. ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
  105. if (ret) {
  106. printf("Cannot get cros-ec device (err=%d)\n", ret);
  107. return 1;
  108. }
  109. if (0 == strcmp("id", cmd)) {
  110. char id[MSG_BYTES];
  111. if (cros_ec_read_id(dev, id, sizeof(id))) {
  112. debug("%s: Could not read KBC ID\n", __func__);
  113. return 1;
  114. }
  115. printf("%s\n", id);
  116. } else if (0 == strcmp("info", cmd)) {
  117. struct ec_response_mkbp_info info;
  118. if (cros_ec_info(dev, &info)) {
  119. debug("%s: Could not read KBC info\n", __func__);
  120. return 1;
  121. }
  122. printf("rows = %u\n", info.rows);
  123. printf("cols = %u\n", info.cols);
  124. } else if (0 == strcmp("curimage", cmd)) {
  125. enum ec_current_image image;
  126. if (cros_ec_read_current_image(dev, &image)) {
  127. debug("%s: Could not read KBC image\n", __func__);
  128. return 1;
  129. }
  130. printf("%d\n", image);
  131. } else if (0 == strcmp("hash", cmd)) {
  132. struct ec_response_vboot_hash hash;
  133. int i;
  134. if (cros_ec_read_hash(dev, EC_VBOOT_HASH_OFFSET_ACTIVE, &hash)) {
  135. debug("%s: Could not read KBC hash\n", __func__);
  136. return 1;
  137. }
  138. if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
  139. printf("type: SHA-256\n");
  140. else
  141. printf("type: %d\n", hash.hash_type);
  142. printf("offset: 0x%08x\n", hash.offset);
  143. printf("size: 0x%08x\n", hash.size);
  144. printf("digest: ");
  145. for (i = 0; i < hash.digest_size; i++)
  146. printf("%02x", hash.hash_digest[i]);
  147. printf("\n");
  148. } else if (0 == strcmp("reboot", cmd)) {
  149. int region;
  150. enum ec_reboot_cmd cmd;
  151. if (argc >= 3 && !strcmp(argv[2], "cold")) {
  152. cmd = EC_REBOOT_COLD;
  153. } else {
  154. region = cros_ec_decode_region(argc - 2, argv + 2);
  155. if (region == EC_FLASH_REGION_RO)
  156. cmd = EC_REBOOT_JUMP_RO;
  157. else if (region == EC_FLASH_REGION_ACTIVE)
  158. cmd = EC_REBOOT_JUMP_RW;
  159. else
  160. return CMD_RET_USAGE;
  161. }
  162. if (cros_ec_reboot(dev, cmd, 0)) {
  163. debug("%s: Could not reboot KBC\n", __func__);
  164. return 1;
  165. }
  166. } else if (0 == strcmp("events", cmd)) {
  167. uint32_t events;
  168. if (cros_ec_get_host_events(dev, &events)) {
  169. debug("%s: Could not read host events\n", __func__);
  170. return 1;
  171. }
  172. printf("0x%08x\n", events);
  173. } else if (0 == strcmp("clrevents", cmd)) {
  174. uint32_t events = 0x7fffffff;
  175. if (argc >= 3)
  176. events = simple_strtol(argv[2], NULL, 0);
  177. if (cros_ec_clear_host_events(dev, events)) {
  178. debug("%s: Could not clear host events\n", __func__);
  179. return 1;
  180. }
  181. } else if (0 == strcmp("read", cmd)) {
  182. ret = do_read_write(dev, 0, argc, argv);
  183. if (ret > 0)
  184. return CMD_RET_USAGE;
  185. } else if (0 == strcmp("write", cmd)) {
  186. ret = do_read_write(dev, 1, argc, argv);
  187. if (ret > 0)
  188. return CMD_RET_USAGE;
  189. } else if (0 == strcmp("erase", cmd)) {
  190. int region = cros_ec_decode_region(argc - 2, argv + 2);
  191. uint32_t offset, size;
  192. if (region == -1)
  193. return CMD_RET_USAGE;
  194. if (cros_ec_flash_offset(dev, region, &offset, &size)) {
  195. debug("%s: Could not read region info\n", __func__);
  196. ret = -1;
  197. } else {
  198. ret = cros_ec_flash_erase(dev, offset, size);
  199. if (ret) {
  200. debug("%s: Could not erase region\n",
  201. __func__);
  202. }
  203. }
  204. } else if (0 == strcmp("regioninfo", cmd)) {
  205. int region = cros_ec_decode_region(argc - 2, argv + 2);
  206. uint32_t offset, size;
  207. if (region == -1)
  208. return CMD_RET_USAGE;
  209. ret = cros_ec_flash_offset(dev, region, &offset, &size);
  210. if (ret) {
  211. debug("%s: Could not read region info\n", __func__);
  212. } else {
  213. printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
  214. "RO" : "RW");
  215. printf("Offset: %x\n", offset);
  216. printf("Size: %x\n", size);
  217. }
  218. } else if (0 == strcmp("flashinfo", cmd)) {
  219. struct ec_response_flash_info p;
  220. ret = cros_ec_read_flashinfo(dev, &p);
  221. if (!ret) {
  222. printf("Flash size: %u\n", p.flash_size);
  223. printf("Write block size: %u\n", p.write_block_size);
  224. printf("Erase block size: %u\n", p.erase_block_size);
  225. }
  226. } else if (0 == strcmp("vbnvcontext", cmd)) {
  227. uint8_t block[EC_VBNV_BLOCK_SIZE];
  228. char buf[3];
  229. int i, len;
  230. unsigned long result;
  231. if (argc <= 2) {
  232. ret = cros_ec_read_nvdata(dev, block,
  233. EC_VBNV_BLOCK_SIZE);
  234. if (!ret) {
  235. printf("vbnv_block: ");
  236. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
  237. printf("%02x", block[i]);
  238. putc('\n');
  239. }
  240. } else {
  241. /*
  242. * TODO(clchiou): Move this to a utility function as
  243. * cmd_spi might want to call it.
  244. */
  245. memset(block, 0, EC_VBNV_BLOCK_SIZE);
  246. len = strlen(argv[2]);
  247. buf[2] = '\0';
  248. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
  249. if (i * 2 >= len)
  250. break;
  251. buf[0] = argv[2][i * 2];
  252. if (i * 2 + 1 >= len)
  253. buf[1] = '0';
  254. else
  255. buf[1] = argv[2][i * 2 + 1];
  256. strict_strtoul(buf, 16, &result);
  257. block[i] = result;
  258. }
  259. ret = cros_ec_write_nvdata(dev, block,
  260. EC_VBNV_BLOCK_SIZE);
  261. }
  262. if (ret) {
  263. debug("%s: Could not %s VbNvContext\n", __func__,
  264. argc <= 2 ? "read" : "write");
  265. }
  266. } else if (0 == strcmp("test", cmd)) {
  267. int result = cros_ec_test(dev);
  268. if (result)
  269. printf("Test failed with error %d\n", result);
  270. else
  271. puts("Test passed\n");
  272. } else if (0 == strcmp("version", cmd)) {
  273. struct ec_response_get_version *p;
  274. char *build_string;
  275. ret = cros_ec_read_version(dev, &p);
  276. if (!ret) {
  277. /* Print versions */
  278. printf("RO version: %1.*s\n",
  279. (int)sizeof(p->version_string_ro),
  280. p->version_string_ro);
  281. printf("RW version: %1.*s\n",
  282. (int)sizeof(p->version_string_rw),
  283. p->version_string_rw);
  284. printf("Firmware copy: %s\n",
  285. (p->current_image <
  286. ARRAY_SIZE(ec_current_image_name) ?
  287. ec_current_image_name[p->current_image] :
  288. "?"));
  289. ret = cros_ec_read_build_info(dev, &build_string);
  290. if (!ret)
  291. printf("Build info: %s\n", build_string);
  292. }
  293. } else if (0 == strcmp("ldo", cmd)) {
  294. uint8_t index, state;
  295. char *endp;
  296. if (argc < 3)
  297. return CMD_RET_USAGE;
  298. index = simple_strtoul(argv[2], &endp, 10);
  299. if (*argv[2] == 0 || *endp != 0)
  300. return CMD_RET_USAGE;
  301. if (argc > 3) {
  302. state = simple_strtoul(argv[3], &endp, 10);
  303. if (*argv[3] == 0 || *endp != 0)
  304. return CMD_RET_USAGE;
  305. ret = cros_ec_set_ldo(dev, index, state);
  306. } else {
  307. ret = cros_ec_get_ldo(dev, index, &state);
  308. if (!ret) {
  309. printf("LDO%d: %s\n", index,
  310. state == EC_LDO_STATE_ON ?
  311. "on" : "off");
  312. }
  313. }
  314. if (ret) {
  315. debug("%s: Could not access LDO%d\n", __func__, index);
  316. return ret;
  317. }
  318. } else {
  319. return CMD_RET_USAGE;
  320. }
  321. if (ret < 0) {
  322. printf("Error: CROS-EC command failed (error %d)\n", ret);
  323. ret = 1;
  324. }
  325. return ret;
  326. }
  327. U_BOOT_CMD(
  328. crosec, 6, 1, do_cros_ec,
  329. "CROS-EC utility command",
  330. "init Re-init CROS-EC (done on startup automatically)\n"
  331. "crosec id Read CROS-EC ID\n"
  332. "crosec info Read CROS-EC info\n"
  333. "crosec curimage Read CROS-EC current image\n"
  334. "crosec hash Read CROS-EC hash\n"
  335. "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
  336. "crosec events Read CROS-EC host events\n"
  337. "crosec clrevents [mask] Clear CROS-EC host events\n"
  338. "crosec regioninfo <ro|rw> Read image info\n"
  339. "crosec flashinfo Read flash info\n"
  340. "crosec erase <ro|rw> Erase EC image\n"
  341. "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
  342. "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
  343. "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
  344. "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
  345. "crosec test run tests on cros_ec\n"
  346. "crosec version Read CROS-EC version"
  347. );