cros_ec.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 <flash.h>
  13. #include <log.h>
  14. #include <dm/device-internal.h>
  15. #include <dm/uclass-internal.h>
  16. /* Note: depends on enum ec_current_image */
  17. static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
  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_ACTIVE;
  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 udevice *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(struct cmd_tbl *cmdtp, int flag, int argc,
  87. char *const argv[])
  88. {
  89. struct udevice *dev;
  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, &dev);
  98. if (!ret)
  99. device_remove(dev, DM_REMOVE_NORMAL);
  100. ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
  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, &dev);
  108. if (ret) {
  109. printf("Cannot get cros-ec device (err=%d)\n", ret);
  110. return 1;
  111. }
  112. if (0 == strcmp("id", cmd)) {
  113. char id[MSG_BYTES];
  114. if (cros_ec_read_id(dev, id, sizeof(id))) {
  115. debug("%s: Could not read KBC ID\n", __func__);
  116. return 1;
  117. }
  118. printf("%s\n", id);
  119. } else if (0 == strcmp("info", cmd)) {
  120. struct ec_response_mkbp_info info;
  121. if (cros_ec_info(dev, &info)) {
  122. debug("%s: Could not read KBC info\n", __func__);
  123. return 1;
  124. }
  125. printf("rows = %u\n", info.rows);
  126. printf("cols = %u\n", info.cols);
  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, EC_VBOOT_HASH_OFFSET_ACTIVE, &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_ACTIVE)
  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_nvdata(dev, block,
  236. EC_VBNV_BLOCK_SIZE);
  237. if (!ret) {
  238. printf("vbnv_block: ");
  239. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
  240. printf("%02x", block[i]);
  241. putc('\n');
  242. }
  243. } else {
  244. /*
  245. * TODO(clchiou): Move this to a utility function as
  246. * cmd_spi might want to call it.
  247. */
  248. memset(block, 0, EC_VBNV_BLOCK_SIZE);
  249. len = strlen(argv[2]);
  250. buf[2] = '\0';
  251. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
  252. if (i * 2 >= len)
  253. break;
  254. buf[0] = argv[2][i * 2];
  255. if (i * 2 + 1 >= len)
  256. buf[1] = '0';
  257. else
  258. buf[1] = argv[2][i * 2 + 1];
  259. strict_strtoul(buf, 16, &result);
  260. block[i] = result;
  261. }
  262. ret = cros_ec_write_nvdata(dev, block,
  263. EC_VBNV_BLOCK_SIZE);
  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(dev, index, state);
  309. } else {
  310. ret = cros_ec_get_ldo(dev, 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. );