cros_ec.c 13 KB

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