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 <flash.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. /**
  18. * Decode a flash region parameter
  19. *
  20. * @param argc Number of params remaining
  21. * @param argv List of remaining parameters
  22. * @return flash region (EC_FLASH_REGION_...) or -1 on error
  23. */
  24. static int cros_ec_decode_region(int argc, char * const argv[])
  25. {
  26. if (argc > 0) {
  27. if (0 == strcmp(*argv, "rw"))
  28. return EC_FLASH_REGION_ACTIVE;
  29. else if (0 == strcmp(*argv, "ro"))
  30. return EC_FLASH_REGION_RO;
  31. debug("%s: Invalid region '%s'\n", __func__, *argv);
  32. } else {
  33. debug("%s: Missing region parameter\n", __func__);
  34. }
  35. return -1;
  36. }
  37. /**
  38. * Perform a flash read or write command
  39. *
  40. * @param dev CROS-EC device to read/write
  41. * @param is_write 1 do to a write, 0 to do a read
  42. * @param argc Number of arguments
  43. * @param argv Arguments (2 is region, 3 is address)
  44. * @return 0 for ok, 1 for a usage error or -ve for ec command error
  45. * (negative EC_RES_...)
  46. */
  47. static int do_read_write(struct udevice *dev, int is_write, int argc,
  48. char * const argv[])
  49. {
  50. uint32_t offset, size = -1U, region_size;
  51. unsigned long addr;
  52. char *endp;
  53. int region;
  54. int ret;
  55. region = cros_ec_decode_region(argc - 2, argv + 2);
  56. if (region == -1)
  57. return 1;
  58. if (argc < 4)
  59. return 1;
  60. addr = simple_strtoul(argv[3], &endp, 16);
  61. if (*argv[3] == 0 || *endp != 0)
  62. return 1;
  63. if (argc > 4) {
  64. size = simple_strtoul(argv[4], &endp, 16);
  65. if (*argv[4] == 0 || *endp != 0)
  66. return 1;
  67. }
  68. ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
  69. if (ret) {
  70. debug("%s: Could not read region info\n", __func__);
  71. return ret;
  72. }
  73. if (size == -1U)
  74. size = region_size;
  75. ret = is_write ?
  76. cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
  77. cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
  78. if (ret) {
  79. debug("%s: Could not %s region\n", __func__,
  80. is_write ? "write" : "read");
  81. return ret;
  82. }
  83. return 0;
  84. }
  85. static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  86. {
  87. struct udevice *dev;
  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, &dev);
  96. if (!ret)
  97. device_remove(dev, DM_REMOVE_NORMAL);
  98. ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
  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, &dev);
  106. if (ret) {
  107. printf("Cannot get cros-ec device (err=%d)\n", ret);
  108. return 1;
  109. }
  110. if (0 == strcmp("id", cmd)) {
  111. char id[MSG_BYTES];
  112. if (cros_ec_read_id(dev, id, sizeof(id))) {
  113. debug("%s: Could not read KBC ID\n", __func__);
  114. return 1;
  115. }
  116. printf("%s\n", id);
  117. } else if (0 == strcmp("info", cmd)) {
  118. struct ec_response_mkbp_info info;
  119. if (cros_ec_info(dev, &info)) {
  120. debug("%s: Could not read KBC info\n", __func__);
  121. return 1;
  122. }
  123. printf("rows = %u\n", info.rows);
  124. printf("cols = %u\n", info.cols);
  125. } else if (0 == strcmp("curimage", cmd)) {
  126. enum ec_current_image image;
  127. if (cros_ec_read_current_image(dev, &image)) {
  128. debug("%s: Could not read KBC image\n", __func__);
  129. return 1;
  130. }
  131. printf("%d\n", image);
  132. } else if (0 == strcmp("hash", cmd)) {
  133. struct ec_response_vboot_hash hash;
  134. int i;
  135. if (cros_ec_read_hash(dev, EC_VBOOT_HASH_OFFSET_ACTIVE, &hash)) {
  136. debug("%s: Could not read KBC hash\n", __func__);
  137. return 1;
  138. }
  139. if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
  140. printf("type: SHA-256\n");
  141. else
  142. printf("type: %d\n", hash.hash_type);
  143. printf("offset: 0x%08x\n", hash.offset);
  144. printf("size: 0x%08x\n", hash.size);
  145. printf("digest: ");
  146. for (i = 0; i < hash.digest_size; i++)
  147. printf("%02x", hash.hash_digest[i]);
  148. printf("\n");
  149. } else if (0 == strcmp("reboot", cmd)) {
  150. int region;
  151. enum ec_reboot_cmd cmd;
  152. if (argc >= 3 && !strcmp(argv[2], "cold")) {
  153. cmd = EC_REBOOT_COLD;
  154. } else {
  155. region = cros_ec_decode_region(argc - 2, argv + 2);
  156. if (region == EC_FLASH_REGION_RO)
  157. cmd = EC_REBOOT_JUMP_RO;
  158. else if (region == EC_FLASH_REGION_ACTIVE)
  159. cmd = EC_REBOOT_JUMP_RW;
  160. else
  161. return CMD_RET_USAGE;
  162. }
  163. if (cros_ec_reboot(dev, cmd, 0)) {
  164. debug("%s: Could not reboot KBC\n", __func__);
  165. return 1;
  166. }
  167. } else if (0 == strcmp("events", cmd)) {
  168. uint32_t events;
  169. if (cros_ec_get_host_events(dev, &events)) {
  170. debug("%s: Could not read host events\n", __func__);
  171. return 1;
  172. }
  173. printf("0x%08x\n", events);
  174. } else if (0 == strcmp("clrevents", cmd)) {
  175. uint32_t events = 0x7fffffff;
  176. if (argc >= 3)
  177. events = simple_strtol(argv[2], NULL, 0);
  178. if (cros_ec_clear_host_events(dev, events)) {
  179. debug("%s: Could not clear host events\n", __func__);
  180. return 1;
  181. }
  182. } else if (0 == strcmp("read", cmd)) {
  183. ret = do_read_write(dev, 0, argc, argv);
  184. if (ret > 0)
  185. return CMD_RET_USAGE;
  186. } else if (0 == strcmp("write", cmd)) {
  187. ret = do_read_write(dev, 1, argc, argv);
  188. if (ret > 0)
  189. return CMD_RET_USAGE;
  190. } else if (0 == strcmp("erase", cmd)) {
  191. int region = cros_ec_decode_region(argc - 2, argv + 2);
  192. uint32_t offset, size;
  193. if (region == -1)
  194. return CMD_RET_USAGE;
  195. if (cros_ec_flash_offset(dev, region, &offset, &size)) {
  196. debug("%s: Could not read region info\n", __func__);
  197. ret = -1;
  198. } else {
  199. ret = cros_ec_flash_erase(dev, offset, size);
  200. if (ret) {
  201. debug("%s: Could not erase region\n",
  202. __func__);
  203. }
  204. }
  205. } else if (0 == strcmp("regioninfo", cmd)) {
  206. int region = cros_ec_decode_region(argc - 2, argv + 2);
  207. uint32_t offset, size;
  208. if (region == -1)
  209. return CMD_RET_USAGE;
  210. ret = cros_ec_flash_offset(dev, region, &offset, &size);
  211. if (ret) {
  212. debug("%s: Could not read region info\n", __func__);
  213. } else {
  214. printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
  215. "RO" : "RW");
  216. printf("Offset: %x\n", offset);
  217. printf("Size: %x\n", size);
  218. }
  219. } else if (0 == strcmp("flashinfo", cmd)) {
  220. struct ec_response_flash_info p;
  221. ret = cros_ec_read_flashinfo(dev, &p);
  222. if (!ret) {
  223. printf("Flash size: %u\n", p.flash_size);
  224. printf("Write block size: %u\n", p.write_block_size);
  225. printf("Erase block size: %u\n", p.erase_block_size);
  226. }
  227. } else if (0 == strcmp("vbnvcontext", cmd)) {
  228. uint8_t block[EC_VBNV_BLOCK_SIZE];
  229. char buf[3];
  230. int i, len;
  231. unsigned long result;
  232. if (argc <= 2) {
  233. ret = cros_ec_read_nvdata(dev, block,
  234. EC_VBNV_BLOCK_SIZE);
  235. if (!ret) {
  236. printf("vbnv_block: ");
  237. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
  238. printf("%02x", block[i]);
  239. putc('\n');
  240. }
  241. } else {
  242. /*
  243. * TODO(clchiou): Move this to a utility function as
  244. * cmd_spi might want to call it.
  245. */
  246. memset(block, 0, EC_VBNV_BLOCK_SIZE);
  247. len = strlen(argv[2]);
  248. buf[2] = '\0';
  249. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
  250. if (i * 2 >= len)
  251. break;
  252. buf[0] = argv[2][i * 2];
  253. if (i * 2 + 1 >= len)
  254. buf[1] = '0';
  255. else
  256. buf[1] = argv[2][i * 2 + 1];
  257. strict_strtoul(buf, 16, &result);
  258. block[i] = result;
  259. }
  260. ret = cros_ec_write_nvdata(dev, block,
  261. EC_VBNV_BLOCK_SIZE);
  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(dev, index, state);
  307. } else {
  308. ret = cros_ec_get_ldo(dev, 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. );