cros_ec.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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 <log.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 = hextoul(argv[3], &endp);
  61. if (*argv[3] == 0 || *endp != 0)
  62. return 1;
  63. if (argc > 4) {
  64. size = hextoul(argv[4], &endp);
  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 const char *const feat_name[64] = {
  86. "limited",
  87. "flash",
  88. "pwm_fan",
  89. "pwm_keyb",
  90. "lightbar",
  91. "led",
  92. "motion_sense",
  93. "keyb",
  94. "pstore",
  95. "port80",
  96. "thermal",
  97. "bklight_switch",
  98. "wifi_switch",
  99. "host_events",
  100. "gpio",
  101. "i2c",
  102. "charger",
  103. "battery",
  104. "smart_battery",
  105. "hang_detect",
  106. "pmu",
  107. "sub_mcu",
  108. "usb_pd",
  109. "usb_mux",
  110. "motion_sense_fifo",
  111. "vstore",
  112. "usbc_ss_mux_virtual",
  113. "rtc",
  114. "fingerprint",
  115. "touchpad",
  116. "rwsig",
  117. "device_event",
  118. "unified_wake_masks",
  119. "host_event64",
  120. "exec_in_ram",
  121. "cec",
  122. "motion_sense_tight_timestamps",
  123. "refined_tablet_mode_hysteresis",
  124. "efs2",
  125. "scp",
  126. "ish",
  127. "typec_cmd",
  128. "typec_require_ap_mode_entry",
  129. "typec_mux_require_ap_ack",
  130. };
  131. static int do_show_features(struct udevice *dev)
  132. {
  133. u64 feat;
  134. int ret;
  135. uint i;
  136. ret = cros_ec_get_features(dev, &feat);
  137. if (ret)
  138. return ret;
  139. for (i = 0; i < ARRAY_SIZE(feat_name); i++) {
  140. if (feat & (1ULL << i)) {
  141. if (feat_name[i])
  142. printf("%s\n", feat_name[i]);
  143. else
  144. printf("unknown %d\n", i);
  145. }
  146. }
  147. return 0;
  148. }
  149. static const char *const switch_name[8] = {
  150. "lid open",
  151. "power button pressed",
  152. "write-protect disabled",
  153. NULL,
  154. "dedicated recovery",
  155. NULL,
  156. NULL,
  157. NULL,
  158. };
  159. static int do_show_switches(struct udevice *dev)
  160. {
  161. uint switches;
  162. int ret;
  163. uint i;
  164. ret = cros_ec_get_switches(dev);
  165. if (ret < 0)
  166. return log_msg_ret("get", ret);
  167. switches = ret;
  168. for (i = 0; i < ARRAY_SIZE(switch_name); i++) {
  169. uint mask = 1 << i;
  170. if (switches & mask) {
  171. if (switch_name[i])
  172. printf("%s\n", switch_name[i]);
  173. else
  174. printf("unknown %02x\n", mask);
  175. }
  176. }
  177. return 0;
  178. }
  179. static const char *const event_name[] = {
  180. "lid_closed",
  181. "lid_open",
  182. "power_button",
  183. "ac_connected",
  184. "ac_disconnected",
  185. "battery_low",
  186. "battery_critical",
  187. "battery",
  188. "thermal_threshold",
  189. "device",
  190. "thermal",
  191. "usb_charger",
  192. "key_pressed",
  193. "interface_ready",
  194. "keyboard_recovery",
  195. "thermal_shutdown",
  196. "battery_shutdown",
  197. "throttle_start",
  198. "throttle_stop",
  199. "hang_detect",
  200. "hang_reboot",
  201. "pd_mcu",
  202. "battery_status",
  203. "panic",
  204. "keyboard_fastboot",
  205. "rtc",
  206. "mkbp",
  207. "usb_mux",
  208. "mode_change",
  209. "keyboard_recovery_hw_reinit",
  210. "extended",
  211. "invalid",
  212. };
  213. static int do_show_events(struct udevice *dev)
  214. {
  215. u32 events;
  216. int ret;
  217. uint i;
  218. ret = cros_ec_get_host_events(dev, &events);
  219. if (ret)
  220. return ret;
  221. printf("%08x\n", events);
  222. for (i = 0; i < ARRAY_SIZE(event_name); i++) {
  223. enum host_event_code code = i + 1;
  224. u64 mask = EC_HOST_EVENT_MASK(code);
  225. if (events & mask) {
  226. if (event_name[i])
  227. printf("%s\n", event_name[i]);
  228. else
  229. printf("unknown code %#x\n", code);
  230. }
  231. }
  232. return 0;
  233. }
  234. static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
  235. char *const argv[])
  236. {
  237. struct udevice *dev;
  238. const char *cmd;
  239. int ret = 0;
  240. if (argc < 2)
  241. return CMD_RET_USAGE;
  242. cmd = argv[1];
  243. if (0 == strcmp("init", cmd)) {
  244. /* Remove any existing device */
  245. ret = uclass_find_device(UCLASS_CROS_EC, 0, &dev);
  246. if (!ret)
  247. device_remove(dev, DM_REMOVE_NORMAL);
  248. ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
  249. if (ret) {
  250. printf("Could not init cros_ec device (err %d)\n", ret);
  251. return 1;
  252. }
  253. return 0;
  254. }
  255. ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
  256. if (ret) {
  257. printf("Cannot get cros-ec device (err=%d)\n", ret);
  258. return 1;
  259. }
  260. if (0 == strcmp("id", cmd)) {
  261. char id[MSG_BYTES];
  262. if (cros_ec_read_id(dev, id, sizeof(id))) {
  263. debug("%s: Could not read KBC ID\n", __func__);
  264. return 1;
  265. }
  266. printf("%s\n", id);
  267. } else if (0 == strcmp("info", cmd)) {
  268. struct ec_response_mkbp_info info;
  269. if (cros_ec_info(dev, &info)) {
  270. debug("%s: Could not read KBC info\n", __func__);
  271. return 1;
  272. }
  273. printf("rows = %u\n", info.rows);
  274. printf("cols = %u\n", info.cols);
  275. } else if (!strcmp("features", cmd)) {
  276. ret = do_show_features(dev);
  277. if (ret)
  278. printf("Error: %d\n", ret);
  279. } else if (!strcmp("switches", cmd)) {
  280. ret = do_show_switches(dev);
  281. if (ret)
  282. printf("Error: %d\n", ret);
  283. } else if (0 == strcmp("curimage", cmd)) {
  284. enum ec_current_image image;
  285. if (cros_ec_read_current_image(dev, &image)) {
  286. debug("%s: Could not read KBC image\n", __func__);
  287. return 1;
  288. }
  289. printf("%d\n", image);
  290. } else if (0 == strcmp("hash", cmd)) {
  291. struct ec_response_vboot_hash hash;
  292. int i;
  293. if (cros_ec_read_hash(dev, EC_VBOOT_HASH_OFFSET_ACTIVE, &hash)) {
  294. debug("%s: Could not read KBC hash\n", __func__);
  295. return 1;
  296. }
  297. if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
  298. printf("type: SHA-256\n");
  299. else
  300. printf("type: %d\n", hash.hash_type);
  301. printf("offset: 0x%08x\n", hash.offset);
  302. printf("size: 0x%08x\n", hash.size);
  303. printf("digest: ");
  304. for (i = 0; i < hash.digest_size; i++)
  305. printf("%02x", hash.hash_digest[i]);
  306. printf("\n");
  307. } else if (0 == strcmp("reboot", cmd)) {
  308. int region;
  309. enum ec_reboot_cmd cmd;
  310. if (argc >= 3 && !strcmp(argv[2], "cold")) {
  311. cmd = EC_REBOOT_COLD;
  312. } else {
  313. region = cros_ec_decode_region(argc - 2, argv + 2);
  314. if (region == EC_FLASH_REGION_RO)
  315. cmd = EC_REBOOT_JUMP_RO;
  316. else if (region == EC_FLASH_REGION_ACTIVE)
  317. cmd = EC_REBOOT_JUMP_RW;
  318. else
  319. return CMD_RET_USAGE;
  320. }
  321. if (cros_ec_reboot(dev, cmd, 0)) {
  322. debug("%s: Could not reboot KBC\n", __func__);
  323. return 1;
  324. }
  325. } else if (0 == strcmp("events", cmd)) {
  326. ret = do_show_events(dev);
  327. if (ret)
  328. printf("Error: %d\n", ret);
  329. } else if (0 == strcmp("clrevents", cmd)) {
  330. uint32_t events = 0x7fffffff;
  331. if (argc >= 3)
  332. events = simple_strtol(argv[2], NULL, 0);
  333. if (cros_ec_clear_host_events(dev, events)) {
  334. debug("%s: Could not clear host events\n", __func__);
  335. return 1;
  336. }
  337. } else if (0 == strcmp("read", cmd)) {
  338. ret = do_read_write(dev, 0, argc, argv);
  339. if (ret > 0)
  340. return CMD_RET_USAGE;
  341. } else if (0 == strcmp("write", cmd)) {
  342. ret = do_read_write(dev, 1, argc, argv);
  343. if (ret > 0)
  344. return CMD_RET_USAGE;
  345. } else if (0 == strcmp("erase", cmd)) {
  346. int region = cros_ec_decode_region(argc - 2, argv + 2);
  347. uint32_t offset, size;
  348. if (region == -1)
  349. return CMD_RET_USAGE;
  350. if (cros_ec_flash_offset(dev, region, &offset, &size)) {
  351. debug("%s: Could not read region info\n", __func__);
  352. ret = -1;
  353. } else {
  354. ret = cros_ec_flash_erase(dev, offset, size);
  355. if (ret) {
  356. debug("%s: Could not erase region\n",
  357. __func__);
  358. }
  359. }
  360. } else if (0 == strcmp("regioninfo", cmd)) {
  361. int region = cros_ec_decode_region(argc - 2, argv + 2);
  362. uint32_t offset, size;
  363. if (region == -1)
  364. return CMD_RET_USAGE;
  365. ret = cros_ec_flash_offset(dev, region, &offset, &size);
  366. if (ret) {
  367. debug("%s: Could not read region info\n", __func__);
  368. } else {
  369. printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
  370. "RO" : "RW");
  371. printf("Offset: %x\n", offset);
  372. printf("Size: %x\n", size);
  373. }
  374. } else if (0 == strcmp("flashinfo", cmd)) {
  375. struct ec_response_flash_info p;
  376. ret = cros_ec_read_flashinfo(dev, &p);
  377. if (!ret) {
  378. printf("Flash size: %u\n", p.flash_size);
  379. printf("Write block size: %u\n", p.write_block_size);
  380. printf("Erase block size: %u\n", p.erase_block_size);
  381. }
  382. } else if (0 == strcmp("vbnvcontext", cmd)) {
  383. uint8_t block[EC_VBNV_BLOCK_SIZE];
  384. char buf[3];
  385. int i, len;
  386. unsigned long result;
  387. if (argc <= 2) {
  388. ret = cros_ec_read_nvdata(dev, block,
  389. EC_VBNV_BLOCK_SIZE);
  390. if (!ret) {
  391. printf("vbnv_block: ");
  392. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
  393. printf("%02x", block[i]);
  394. putc('\n');
  395. }
  396. } else {
  397. /*
  398. * TODO(clchiou): Move this to a utility function as
  399. * cmd_spi might want to call it.
  400. */
  401. memset(block, 0, EC_VBNV_BLOCK_SIZE);
  402. len = strlen(argv[2]);
  403. buf[2] = '\0';
  404. for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
  405. if (i * 2 >= len)
  406. break;
  407. buf[0] = argv[2][i * 2];
  408. if (i * 2 + 1 >= len)
  409. buf[1] = '0';
  410. else
  411. buf[1] = argv[2][i * 2 + 1];
  412. strict_strtoul(buf, 16, &result);
  413. block[i] = result;
  414. }
  415. ret = cros_ec_write_nvdata(dev, block,
  416. EC_VBNV_BLOCK_SIZE);
  417. }
  418. if (ret) {
  419. debug("%s: Could not %s VbNvContext\n", __func__,
  420. argc <= 2 ? "read" : "write");
  421. }
  422. } else if (0 == strcmp("test", cmd)) {
  423. int result = cros_ec_test(dev);
  424. if (result)
  425. printf("Test failed with error %d\n", result);
  426. else
  427. puts("Test passed\n");
  428. } else if (0 == strcmp("version", cmd)) {
  429. struct ec_response_get_version *p;
  430. char *build_string;
  431. ret = cros_ec_read_version(dev, &p);
  432. if (!ret) {
  433. /* Print versions */
  434. printf("RO version: %1.*s\n",
  435. (int)sizeof(p->version_string_ro),
  436. p->version_string_ro);
  437. printf("RW version: %1.*s\n",
  438. (int)sizeof(p->version_string_rw),
  439. p->version_string_rw);
  440. printf("Firmware copy: %s\n",
  441. (p->current_image <
  442. ARRAY_SIZE(ec_current_image_name) ?
  443. ec_current_image_name[p->current_image] :
  444. "?"));
  445. ret = cros_ec_read_build_info(dev, &build_string);
  446. if (!ret)
  447. printf("Build info: %s\n", build_string);
  448. }
  449. } else if (0 == strcmp("ldo", cmd)) {
  450. uint8_t index, state;
  451. char *endp;
  452. if (argc < 3)
  453. return CMD_RET_USAGE;
  454. index = dectoul(argv[2], &endp);
  455. if (*argv[2] == 0 || *endp != 0)
  456. return CMD_RET_USAGE;
  457. if (argc > 3) {
  458. state = dectoul(argv[3], &endp);
  459. if (*argv[3] == 0 || *endp != 0)
  460. return CMD_RET_USAGE;
  461. ret = cros_ec_set_ldo(dev, index, state);
  462. } else {
  463. ret = cros_ec_get_ldo(dev, index, &state);
  464. if (!ret) {
  465. printf("LDO%d: %s\n", index,
  466. state == EC_LDO_STATE_ON ?
  467. "on" : "off");
  468. }
  469. }
  470. if (ret) {
  471. debug("%s: Could not access LDO%d\n", __func__, index);
  472. return ret;
  473. }
  474. } else if (!strcmp("sku", cmd)) {
  475. ret = cros_ec_get_sku_id(dev);
  476. if (ret >= 0) {
  477. printf("%d\n", ret);
  478. ret = 0;
  479. } else {
  480. printf("Error: %d\n", ret);
  481. }
  482. } else {
  483. return CMD_RET_USAGE;
  484. }
  485. if (ret < 0) {
  486. printf("Error: CROS-EC command failed (error %d)\n", ret);
  487. ret = 1;
  488. }
  489. return ret;
  490. }
  491. U_BOOT_CMD(
  492. crosec, 6, 1, do_cros_ec,
  493. "CROS-EC utility command",
  494. "init Re-init CROS-EC (done on startup automatically)\n"
  495. "crosec id Read CROS-EC ID\n"
  496. "crosec info Read CROS-EC info\n"
  497. "crosec features Read CROS-EC features\n"
  498. "crosec switches Read CROS-EC switches\n"
  499. "crosec curimage Read CROS-EC current image\n"
  500. "crosec hash Read CROS-EC hash\n"
  501. "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
  502. "crosec events Read CROS-EC host events\n"
  503. "crosec eventsb Read CROS-EC host events_b\n"
  504. "crosec clrevents [mask] Clear CROS-EC host events\n"
  505. "crosec regioninfo <ro|rw> Read image info\n"
  506. "crosec flashinfo Read flash info\n"
  507. "crosec erase <ro|rw> Erase EC image\n"
  508. "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
  509. "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
  510. "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
  511. "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
  512. "crosec sku Read board SKU ID\n"
  513. "crosec test run tests on cros_ec\n"
  514. "crosec version Read CROS-EC version"
  515. );