123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Chromium OS cros_ec driver
- *
- * Copyright (c) 2016 The Chromium OS Authors.
- * Copyright (c) 2016 National Instruments Corp
- */
- #include <common.h>
- #include <command.h>
- #include <cros_ec.h>
- #include <dm.h>
- #include <flash.h>
- #include <log.h>
- #include <dm/device-internal.h>
- #include <dm/uclass-internal.h>
- /* Note: depends on enum ec_current_image */
- static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
- /**
- * Decode a flash region parameter
- *
- * @param argc Number of params remaining
- * @param argv List of remaining parameters
- * @return flash region (EC_FLASH_REGION_...) or -1 on error
- */
- static int cros_ec_decode_region(int argc, char *const argv[])
- {
- if (argc > 0) {
- if (0 == strcmp(*argv, "rw"))
- return EC_FLASH_REGION_ACTIVE;
- else if (0 == strcmp(*argv, "ro"))
- return EC_FLASH_REGION_RO;
- debug("%s: Invalid region '%s'\n", __func__, *argv);
- } else {
- debug("%s: Missing region parameter\n", __func__);
- }
- return -1;
- }
- /**
- * Perform a flash read or write command
- *
- * @param dev CROS-EC device to read/write
- * @param is_write 1 do to a write, 0 to do a read
- * @param argc Number of arguments
- * @param argv Arguments (2 is region, 3 is address)
- * @return 0 for ok, 1 for a usage error or -ve for ec command error
- * (negative EC_RES_...)
- */
- static int do_read_write(struct udevice *dev, int is_write, int argc,
- char *const argv[])
- {
- uint32_t offset, size = -1U, region_size;
- unsigned long addr;
- char *endp;
- int region;
- int ret;
- region = cros_ec_decode_region(argc - 2, argv + 2);
- if (region == -1)
- return 1;
- if (argc < 4)
- return 1;
- addr = hextoul(argv[3], &endp);
- if (*argv[3] == 0 || *endp != 0)
- return 1;
- if (argc > 4) {
- size = hextoul(argv[4], &endp);
- if (*argv[4] == 0 || *endp != 0)
- return 1;
- }
- ret = cros_ec_flash_offset(dev, region, &offset, ®ion_size);
- if (ret) {
- debug("%s: Could not read region info\n", __func__);
- return ret;
- }
- if (size == -1U)
- size = region_size;
- ret = is_write ?
- cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
- cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
- if (ret) {
- debug("%s: Could not %s region\n", __func__,
- is_write ? "write" : "read");
- return ret;
- }
- return 0;
- }
- static const char *const feat_name[64] = {
- "limited",
- "flash",
- "pwm_fan",
- "pwm_keyb",
- "lightbar",
- "led",
- "motion_sense",
- "keyb",
- "pstore",
- "port80",
- "thermal",
- "bklight_switch",
- "wifi_switch",
- "host_events",
- "gpio",
- "i2c",
- "charger",
- "battery",
- "smart_battery",
- "hang_detect",
- "pmu",
- "sub_mcu",
- "usb_pd",
- "usb_mux",
- "motion_sense_fifo",
- "vstore",
- "usbc_ss_mux_virtual",
- "rtc",
- "fingerprint",
- "touchpad",
- "rwsig",
- "device_event",
- "unified_wake_masks",
- "host_event64",
- "exec_in_ram",
- "cec",
- "motion_sense_tight_timestamps",
- "refined_tablet_mode_hysteresis",
- "efs2",
- "scp",
- "ish",
- "typec_cmd",
- "typec_require_ap_mode_entry",
- "typec_mux_require_ap_ack",
- };
- static int do_show_features(struct udevice *dev)
- {
- u64 feat;
- int ret;
- uint i;
- ret = cros_ec_get_features(dev, &feat);
- if (ret)
- return ret;
- for (i = 0; i < ARRAY_SIZE(feat_name); i++) {
- if (feat & (1ULL << i)) {
- if (feat_name[i])
- printf("%s\n", feat_name[i]);
- else
- printf("unknown %d\n", i);
- }
- }
- return 0;
- }
- static const char *const switch_name[8] = {
- "lid open",
- "power button pressed",
- "write-protect disabled",
- NULL,
- "dedicated recovery",
- NULL,
- NULL,
- NULL,
- };
- static int do_show_switches(struct udevice *dev)
- {
- uint switches;
- int ret;
- uint i;
- ret = cros_ec_get_switches(dev);
- if (ret < 0)
- return log_msg_ret("get", ret);
- switches = ret;
- for (i = 0; i < ARRAY_SIZE(switch_name); i++) {
- uint mask = 1 << i;
- if (switches & mask) {
- if (switch_name[i])
- printf("%s\n", switch_name[i]);
- else
- printf("unknown %02x\n", mask);
- }
- }
- return 0;
- }
- static const char *const event_name[] = {
- "lid_closed",
- "lid_open",
- "power_button",
- "ac_connected",
- "ac_disconnected",
- "battery_low",
- "battery_critical",
- "battery",
- "thermal_threshold",
- "device",
- "thermal",
- "usb_charger",
- "key_pressed",
- "interface_ready",
- "keyboard_recovery",
- "thermal_shutdown",
- "battery_shutdown",
- "throttle_start",
- "throttle_stop",
- "hang_detect",
- "hang_reboot",
- "pd_mcu",
- "battery_status",
- "panic",
- "keyboard_fastboot",
- "rtc",
- "mkbp",
- "usb_mux",
- "mode_change",
- "keyboard_recovery_hw_reinit",
- "extended",
- "invalid",
- };
- static int do_show_events(struct udevice *dev)
- {
- u32 events;
- int ret;
- uint i;
- ret = cros_ec_get_host_events(dev, &events);
- if (ret)
- return ret;
- printf("%08x\n", events);
- for (i = 0; i < ARRAY_SIZE(event_name); i++) {
- enum host_event_code code = i + 1;
- u64 mask = EC_HOST_EVENT_MASK(code);
- if (events & mask) {
- if (event_name[i])
- printf("%s\n", event_name[i]);
- else
- printf("unknown code %#x\n", code);
- }
- }
- return 0;
- }
- static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[])
- {
- struct udevice *dev;
- const char *cmd;
- int ret = 0;
- if (argc < 2)
- return CMD_RET_USAGE;
- cmd = argv[1];
- if (0 == strcmp("init", cmd)) {
- /* Remove any existing device */
- ret = uclass_find_device(UCLASS_CROS_EC, 0, &dev);
- if (!ret)
- device_remove(dev, DM_REMOVE_NORMAL);
- ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
- if (ret) {
- printf("Could not init cros_ec device (err %d)\n", ret);
- return 1;
- }
- return 0;
- }
- ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
- if (ret) {
- printf("Cannot get cros-ec device (err=%d)\n", ret);
- return 1;
- }
- if (0 == strcmp("id", cmd)) {
- char id[MSG_BYTES];
- if (cros_ec_read_id(dev, id, sizeof(id))) {
- debug("%s: Could not read KBC ID\n", __func__);
- return 1;
- }
- printf("%s\n", id);
- } else if (0 == strcmp("info", cmd)) {
- struct ec_response_mkbp_info info;
- if (cros_ec_info(dev, &info)) {
- debug("%s: Could not read KBC info\n", __func__);
- return 1;
- }
- printf("rows = %u\n", info.rows);
- printf("cols = %u\n", info.cols);
- } else if (!strcmp("features", cmd)) {
- ret = do_show_features(dev);
- if (ret)
- printf("Error: %d\n", ret);
- } else if (!strcmp("switches", cmd)) {
- ret = do_show_switches(dev);
- if (ret)
- printf("Error: %d\n", ret);
- } else if (0 == strcmp("curimage", cmd)) {
- enum ec_current_image image;
- if (cros_ec_read_current_image(dev, &image)) {
- debug("%s: Could not read KBC image\n", __func__);
- return 1;
- }
- printf("%d\n", image);
- } else if (0 == strcmp("hash", cmd)) {
- struct ec_response_vboot_hash hash;
- int i;
- if (cros_ec_read_hash(dev, EC_VBOOT_HASH_OFFSET_ACTIVE, &hash)) {
- debug("%s: Could not read KBC hash\n", __func__);
- return 1;
- }
- if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
- printf("type: SHA-256\n");
- else
- printf("type: %d\n", hash.hash_type);
- printf("offset: 0x%08x\n", hash.offset);
- printf("size: 0x%08x\n", hash.size);
- printf("digest: ");
- for (i = 0; i < hash.digest_size; i++)
- printf("%02x", hash.hash_digest[i]);
- printf("\n");
- } else if (0 == strcmp("reboot", cmd)) {
- int region;
- enum ec_reboot_cmd cmd;
- if (argc >= 3 && !strcmp(argv[2], "cold")) {
- cmd = EC_REBOOT_COLD;
- } else {
- region = cros_ec_decode_region(argc - 2, argv + 2);
- if (region == EC_FLASH_REGION_RO)
- cmd = EC_REBOOT_JUMP_RO;
- else if (region == EC_FLASH_REGION_ACTIVE)
- cmd = EC_REBOOT_JUMP_RW;
- else
- return CMD_RET_USAGE;
- }
- if (cros_ec_reboot(dev, cmd, 0)) {
- debug("%s: Could not reboot KBC\n", __func__);
- return 1;
- }
- } else if (0 == strcmp("events", cmd)) {
- ret = do_show_events(dev);
- if (ret)
- printf("Error: %d\n", ret);
- } else if (0 == strcmp("clrevents", cmd)) {
- uint32_t events = 0x7fffffff;
- if (argc >= 3)
- events = simple_strtol(argv[2], NULL, 0);
- if (cros_ec_clear_host_events(dev, events)) {
- debug("%s: Could not clear host events\n", __func__);
- return 1;
- }
- } else if (0 == strcmp("read", cmd)) {
- ret = do_read_write(dev, 0, argc, argv);
- if (ret > 0)
- return CMD_RET_USAGE;
- } else if (0 == strcmp("write", cmd)) {
- ret = do_read_write(dev, 1, argc, argv);
- if (ret > 0)
- return CMD_RET_USAGE;
- } else if (0 == strcmp("erase", cmd)) {
- int region = cros_ec_decode_region(argc - 2, argv + 2);
- uint32_t offset, size;
- if (region == -1)
- return CMD_RET_USAGE;
- if (cros_ec_flash_offset(dev, region, &offset, &size)) {
- debug("%s: Could not read region info\n", __func__);
- ret = -1;
- } else {
- ret = cros_ec_flash_erase(dev, offset, size);
- if (ret) {
- debug("%s: Could not erase region\n",
- __func__);
- }
- }
- } else if (0 == strcmp("regioninfo", cmd)) {
- int region = cros_ec_decode_region(argc - 2, argv + 2);
- uint32_t offset, size;
- if (region == -1)
- return CMD_RET_USAGE;
- ret = cros_ec_flash_offset(dev, region, &offset, &size);
- if (ret) {
- debug("%s: Could not read region info\n", __func__);
- } else {
- printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
- "RO" : "RW");
- printf("Offset: %x\n", offset);
- printf("Size: %x\n", size);
- }
- } else if (0 == strcmp("flashinfo", cmd)) {
- struct ec_response_flash_info p;
- ret = cros_ec_read_flashinfo(dev, &p);
- if (!ret) {
- printf("Flash size: %u\n", p.flash_size);
- printf("Write block size: %u\n", p.write_block_size);
- printf("Erase block size: %u\n", p.erase_block_size);
- }
- } else if (0 == strcmp("vbnvcontext", cmd)) {
- uint8_t block[EC_VBNV_BLOCK_SIZE];
- char buf[3];
- int i, len;
- unsigned long result;
- if (argc <= 2) {
- ret = cros_ec_read_nvdata(dev, block,
- EC_VBNV_BLOCK_SIZE);
- if (!ret) {
- printf("vbnv_block: ");
- for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
- printf("%02x", block[i]);
- putc('\n');
- }
- } else {
- /*
- * TODO(clchiou): Move this to a utility function as
- * cmd_spi might want to call it.
- */
- memset(block, 0, EC_VBNV_BLOCK_SIZE);
- len = strlen(argv[2]);
- buf[2] = '\0';
- for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
- if (i * 2 >= len)
- break;
- buf[0] = argv[2][i * 2];
- if (i * 2 + 1 >= len)
- buf[1] = '0';
- else
- buf[1] = argv[2][i * 2 + 1];
- strict_strtoul(buf, 16, &result);
- block[i] = result;
- }
- ret = cros_ec_write_nvdata(dev, block,
- EC_VBNV_BLOCK_SIZE);
- }
- if (ret) {
- debug("%s: Could not %s VbNvContext\n", __func__,
- argc <= 2 ? "read" : "write");
- }
- } else if (0 == strcmp("test", cmd)) {
- int result = cros_ec_test(dev);
- if (result)
- printf("Test failed with error %d\n", result);
- else
- puts("Test passed\n");
- } else if (0 == strcmp("version", cmd)) {
- struct ec_response_get_version *p;
- char *build_string;
- ret = cros_ec_read_version(dev, &p);
- if (!ret) {
- /* Print versions */
- printf("RO version: %1.*s\n",
- (int)sizeof(p->version_string_ro),
- p->version_string_ro);
- printf("RW version: %1.*s\n",
- (int)sizeof(p->version_string_rw),
- p->version_string_rw);
- printf("Firmware copy: %s\n",
- (p->current_image <
- ARRAY_SIZE(ec_current_image_name) ?
- ec_current_image_name[p->current_image] :
- "?"));
- ret = cros_ec_read_build_info(dev, &build_string);
- if (!ret)
- printf("Build info: %s\n", build_string);
- }
- } else if (0 == strcmp("ldo", cmd)) {
- uint8_t index, state;
- char *endp;
- if (argc < 3)
- return CMD_RET_USAGE;
- index = dectoul(argv[2], &endp);
- if (*argv[2] == 0 || *endp != 0)
- return CMD_RET_USAGE;
- if (argc > 3) {
- state = dectoul(argv[3], &endp);
- if (*argv[3] == 0 || *endp != 0)
- return CMD_RET_USAGE;
- ret = cros_ec_set_ldo(dev, index, state);
- } else {
- ret = cros_ec_get_ldo(dev, index, &state);
- if (!ret) {
- printf("LDO%d: %s\n", index,
- state == EC_LDO_STATE_ON ?
- "on" : "off");
- }
- }
- if (ret) {
- debug("%s: Could not access LDO%d\n", __func__, index);
- return ret;
- }
- } else if (!strcmp("sku", cmd)) {
- ret = cros_ec_get_sku_id(dev);
- if (ret >= 0) {
- printf("%d\n", ret);
- ret = 0;
- } else {
- printf("Error: %d\n", ret);
- }
- } else {
- return CMD_RET_USAGE;
- }
- if (ret < 0) {
- printf("Error: CROS-EC command failed (error %d)\n", ret);
- ret = 1;
- }
- return ret;
- }
- U_BOOT_CMD(
- crosec, 6, 1, do_cros_ec,
- "CROS-EC utility command",
- "init Re-init CROS-EC (done on startup automatically)\n"
- "crosec id Read CROS-EC ID\n"
- "crosec info Read CROS-EC info\n"
- "crosec features Read CROS-EC features\n"
- "crosec switches Read CROS-EC switches\n"
- "crosec curimage Read CROS-EC current image\n"
- "crosec hash Read CROS-EC hash\n"
- "crosec reboot [rw | ro | cold] Reboot CROS-EC\n"
- "crosec events Read CROS-EC host events\n"
- "crosec eventsb Read CROS-EC host events_b\n"
- "crosec clrevents [mask] Clear CROS-EC host events\n"
- "crosec regioninfo <ro|rw> Read image info\n"
- "crosec flashinfo Read flash info\n"
- "crosec erase <ro|rw> Erase EC image\n"
- "crosec read <ro|rw> <addr> [<size>] Read EC image\n"
- "crosec write <ro|rw> <addr> [<size>] Write EC image\n"
- "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
- "crosec ldo <idx> [<state>] Switch/Read LDO state\n"
- "crosec sku Read board SKU ID\n"
- "crosec test run tests on cros_ec\n"
- "crosec version Read CROS-EC version"
- );
|