/** * Get the versions of the command supported by the EC. * * @param cmd Command * @param pmask Destination for version mask; will be set to 0 on * error. * @return 0 if success, <0 if error */ int ec_get_cmd_versions(int cmd, uint32_t *pmask) { struct ec_params_get_cmd_versions_v1 pver_v1; struct ec_params_get_cmd_versions pver; struct ec_response_get_cmd_versions rver; int rv; *pmask = 0; pver_v1.cmd = cmd; rv = ec_command(EC_CMD_GET_CMD_VERSIONS, 1, &pver_v1, sizeof(pver_v1), &rver, sizeof(rver)); if (rv < 0) { pver.cmd = cmd; rv = ec_command(EC_CMD_GET_CMD_VERSIONS, 0, &pver, sizeof(pver), &rver, sizeof(rver)); } if (rv < 0) return rv; *pmask = rver.version_mask; return 0; }
static int fake_readmem(int offset, int bytes, void *dest) { struct ec_params_read_memmap p; int c; char *buf; p.offset = offset; if (bytes) { p.size = bytes; c = ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p), dest, p.size); if (c < 0) return c; return p.size; } p.size = EC_MEMMAP_TEXT_MAX; c = ec_command(EC_CMD_READ_MEMMAP, 0, &p, sizeof(p), dest, p.size); if (c < 0) return c; buf = dest; for (c = 0; c < EC_MEMMAP_TEXT_MAX; c++) { if (buf[c] == 0) return c; } buf[EC_MEMMAP_TEXT_MAX - 1] = 0; return EC_MEMMAP_TEXT_MAX - 1; }
int cros_ec_tunnel_i2c_protect(CrosECTunnelI2c *bus) { struct ec_params_i2c_passthru_protect params = { .subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE, .port = bus->remote_bus }; int result; result = ec_command(bus->ec, EC_CMD_I2C_PASSTHRU_PROTECT, 0, ¶ms, sizeof(params), NULL, 0); if (result < 0) return result; return 0; } int cros_ec_tunnel_i2c_protect_status(CrosECTunnelI2c *bus, int *status) { struct ec_params_i2c_passthru_protect params = { .subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_STATUS, .port = bus->remote_bus }; struct ec_response_i2c_passthru_protect response; int result; result = ec_command(bus->ec, EC_CMD_I2C_PASSTHRU_PROTECT, 0, ¶ms, sizeof(params), &response, sizeof(response)); if (result < 0) return result; if (result < sizeof(response)) return -1; *status = response.status; return 0; } CrosECTunnelI2c *new_cros_ec_tunnel_i2c(CrosEc *ec, uint16_t remote_bus) { CrosECTunnelI2c *bus = xzalloc(sizeof(*bus)); assert(ec); bus->ops.transfer = &i2c_transfer; bus->ec = ec; bus->remote_bus = remote_bus; return bus; }
int ec_flash_write(const uint8_t *buf, int offset, int size) { struct ec_params_flash_write *p = (struct ec_params_flash_write *)ec_outbuf; struct ec_response_flash_info info; int pdata_max_size = (int)(ec_max_outsize - sizeof(*p)); int step; int rv; int i; /* * Determine whether we can use version 1 of the command with more * data, or only version 0. */ if (!ec_cmd_version_supported(EC_CMD_FLASH_WRITE, EC_VER_FLASH_WRITE)) pdata_max_size = EC_FLASH_WRITE_VER0_SIZE; /* * Determine step size. This must be a multiple of the write block * size, and must also fit into the host parameter buffer. */ rv = ec_command(EC_CMD_FLASH_INFO, 0, NULL, 0, &info, sizeof(info)); if (rv < 0) return rv; step = (pdata_max_size / info.write_block_size) * info.write_block_size; if (!step) { fprintf(stderr, "Write block size %d > max param size %d\n", info.write_block_size, pdata_max_size); return -1; } /* Write data in chunks */ printf("Write size %d...\n", step); for (i = 0; i < size; i += step) { p->offset = offset + i; p->size = MIN(size - i, step); memcpy(p + 1, buf + i, p->size); rv = ec_command(EC_CMD_FLASH_WRITE, 0, p, sizeof(*p) + p->size, NULL, 0); if (rv < 0) { fprintf(stderr, "Write error at offset %d\n", i); return rv; } } return 0; }
static int get_info(struct sb_fw_update_info *info) { int rv = EC_RES_SUCCESS; int cnt = 0; struct ec_params_sb_fw_update *param = (struct ec_params_sb_fw_update *)ec_outbuf; struct ec_response_sb_fw_update *resp = (struct ec_response_sb_fw_update *)ec_inbuf; param->hdr.subcmd = EC_SB_FW_UPDATE_INFO; do { usleep(SB_FW_UPDATE_DEFAULT_DELAY); rv = ec_command(EC_CMD_SB_FW_UPDATE, 0, param, sizeof(struct ec_sb_fw_update_header), resp, SB_FW_UPDATE_CMD_INFO_SIZE); } while ((rv < 0) && (cnt++ < SB_FW_UPDATE_DEFAULT_RETRY_CNT)); if (rv < 0) { memset(info, 0, SB_FW_UPDATE_CMD_INFO_SIZE); return -EC_RES_ERROR; } memcpy(info, resp->info.data, SB_FW_UPDATE_CMD_INFO_SIZE); return EC_RES_SUCCESS; }
int cros_ec_read_limit_power(struct udevice *dev, int *limit_powerp) { struct ec_params_charge_state p; struct ec_response_charge_state r; int ret; p.cmd = CHARGE_STATE_CMD_GET_PARAM; p.get_param.param = CS_PARAM_LIMIT_POWER; ret = ec_command(dev, EC_CMD_CHARGE_STATE, 0, &p, sizeof(p), &r, sizeof(r)); /* * If our EC doesn't support the LIMIT_POWER parameter, assume that * LIMIT_POWER is not requested. */ if (ret == -EC_RES_INVALID_PARAM || ret == -EC_RES_INVALID_COMMAND) { log_warning("PARAM_LIMIT_POWER not supported by EC\n"); return -ENOSYS; } if (ret != sizeof(r.get_param)) return -EINVAL; *limit_powerp = r.get_param.value; return 0; }
int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan) { if (ec_command(dev, EC_CMD_MKBP_STATE, 0, NULL, 0, scan, sizeof(scan->data)) != sizeof(scan->data)) return -1; return 0; }
int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_mkbp_info *info) { if (ec_command(dev, EC_CMD_MKBP_INFO, 0, NULL, 0, info, sizeof(*info)) != sizeof(*info)) return -1; return 0; }
int ec_flash_erase(int offset, int size) { struct ec_params_flash_erase p; p.offset = offset; p.size = size; return ec_command(EC_CMD_FLASH_ERASE, 0, &p, sizeof(p), NULL, 0); }
int cros_ec_read_hash(struct udevice *dev, uint hash_offset, struct ec_response_vboot_hash *hash) { struct ec_params_vboot_hash p; int rv; p.cmd = EC_VBOOT_HASH_GET; p.offset = hash_offset; if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), hash, sizeof(*hash)) < 0) return -1; /* If the EC is busy calculating the hash, fidget until it's done. */ rv = cros_ec_wait_on_hash_done(dev, hash); if (rv) return rv; /* If the hash is valid, we're done. Otherwise, we have to kick it off * again and wait for it to complete. Note that we explicitly assume * that hashing zero bytes is always wrong, even though that would * produce a valid hash value. */ if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size) return 0; debug("%s: No valid hash (status=%d size=%d). Compute one...\n", __func__, hash->status, hash->size); p.cmd = EC_VBOOT_HASH_START; p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; p.nonce_size = 0; p.offset = hash_offset; if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), hash, sizeof(*hash)) < 0) return -1; rv = cros_ec_wait_on_hash_done(dev, hash); if (rv) return rv; debug("%s: hash done\n", __func__); return 0; }
int cros_ec_entering_mode(struct udevice *dev, int mode) { int rc; rc = ec_command(dev, EC_CMD_ENTERING_MODE, 0, &mode, sizeof(mode), NULL, 0); if (rc) return -1; return 0; }
int CROSKBLIGHTGetBacklight() { struct ec_response_pwm_get_keyboard_backlight r; int rv; rv = ec_command(EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT, 0, NULL, 0, &r, sizeof(r)); if (rv < 0) return rv; return r.percent; }
/** * Read a single block from the flash * * Read a block of data from the EC flash. The size must not exceed the flash * write block size which you can obtain from cros_ec_flash_write_burst_size(). * * The offset starts at 0. You can obtain the region information from * cros_ec_flash_offset() to find out where to read for a particular region. * * @param dev CROS-EC device * @param data Pointer to data buffer to read into * @param offset Offset within flash to read from * @param size Number of bytes to read * @return 0 if ok, -1 on error */ static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset, uint32_t size) { struct ec_params_flash_read p; p.offset = offset; p.size = size; return ec_command(dev, EC_CMD_FLASH_READ, 0, &p, sizeof(p), data, size) >= 0 ? 0 : -1; }
/** * Read back flash parameters * * This function reads back parameters of the flash as reported by the EC * * @param dev Pointer to device * @param info Pointer to output flash info struct */ int cros_ec_read_flashinfo(struct udevice *dev, struct ec_response_flash_info *info) { int ret; ret = ec_command(dev, EC_CMD_FLASH_INFO, 0, NULL, 0, info, sizeof(*info)); if (ret < 0) return ret; return ret < sizeof(*info) ? -1 : 0; }
int cros_ec_battery_cutoff(struct udevice *dev, uint8_t flags) { struct ec_params_battery_cutoff p; int len; p.flags = flags; len = ec_command(dev, EC_CMD_BATTERY_CUT_OFF, 1, &p, sizeof(p), NULL, 0); if (len < 0) return -1; return 0; }
int CROSKBLIGHTSetBacklight(int percent) { struct ec_params_pwm_set_keyboard_backlight p; p.percent = percent; char *e; int rv; rv = ec_command(EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT, 0, &p, sizeof(p), NULL, 0); if (rv < 0) return rv; return 0; }
int cros_ec_set_event_mask(struct udevice *dev, uint type, uint32_t mask) { struct ec_params_host_event_mask req; int ret; req.mask = mask; ret = ec_command(dev, type, 0, &req, sizeof(req), NULL, 0); if (ret < 0) return ret; return 0; }
int cros_ec_config_powerbtn(struct udevice *dev, uint32_t flags) { struct ec_params_config_power_button params; int ret; params.flags = flags; ret = ec_command(dev, EC_CMD_CONFIG_POWER_BUTTON, 0, ¶ms, sizeof(params), NULL, 0); if (ret < 0) return ret; return 0; }
int cros_ec_check_feature(struct udevice *dev, int feature) { struct ec_response_get_features r; int rv; rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, &r, sizeof(r), NULL, 0); if (rv) return rv; if (feature >= 8 * sizeof(r.flags)) return -1; return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature); }
int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block) { struct ec_params_vbnvcontext p; int len; p.op = EC_VBNV_CONTEXT_OP_READ; len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE); if (len < EC_VBNV_BLOCK_SIZE) return -1; return 0; }
int cros_ec_get_event_mask(struct udevice *dev, uint type, uint32_t *mask) { struct ec_response_host_event_mask rsp; int ret; ret = ec_command(dev, type, 0, NULL, 0, &rsp, sizeof(rsp)); if (ret < 0) return ret; else if (ret != sizeof(rsp)) return -EINVAL; *mask = rsp.mask; return 0; }
int cros_ec_flash_protect(struct cros_ec_dev *dev, uint32_t set_mask, uint32_t set_flags, struct ec_response_flash_protect *resp) { struct ec_params_flash_protect params; params.mask = set_mask; params.flags = set_flags; if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT, ¶ms, sizeof(params), resp, sizeof(*resp)) != sizeof(*resp)) return -1; return 0; }
void ckb_ec_intr(void *arg) { struct ckb_softc *sc; sc = arg; if (sc->sc_flags & CKB_FLAG_POLLING) return; ec_command(EC_CMD_MKBP_STATE, sc->scan, sc->cols, sc->scan, sc->cols); (sc->sc_kbd.kb_callback.kc_func) (&sc->sc_kbd, KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg); };
static int send_subcmd(int subcmd) { int rv = EC_RES_SUCCESS; struct ec_params_sb_fw_update *param = (struct ec_params_sb_fw_update *)ec_outbuf; param->hdr.subcmd = subcmd; rv = ec_command(EC_CMD_SB_FW_UPDATE, 0, param, sizeof(struct ec_sb_fw_update_header), NULL, 0); if (rv < 0) { printf("Firmware Update subcmd:%d Error\n", subcmd); return -EC_RES_ERROR; } return EC_RES_SUCCESS; }
int cros_ec_read_nvdata(struct udevice *dev, uint8_t *block, int size) { struct ec_params_vbnvcontext p; int len; if (size != EC_VBNV_BLOCK_SIZE && size != EC_VBNV_BLOCK_SIZE_V2) return -EINVAL; p.op = EC_VBNV_CONTEXT_OP_READ; len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, &p, sizeof(uint32_t) + size, block, size); if (len != size) { log_err("Expected %d bytes, got %d\n", size, len); return -EIO; } return 0; }
static int write_block(struct fw_update_ctrl *fw_update, int offset, int bsize) { int rv; struct ec_params_sb_fw_update *param = (struct ec_params_sb_fw_update *)ec_outbuf; memcpy(param->write.data, fw_update->ptr+offset, bsize); param->hdr.subcmd = EC_SB_FW_UPDATE_WRITE; rv = ec_command(EC_CMD_SB_FW_UPDATE, 0, param, sizeof(struct ec_params_sb_fw_update), NULL, 0); if (rv < 0) { printf("Firmware Update Write Error ptr:%p offset@%x\n", fw_update->ptr, offset); return -EC_RES_ERROR; } return EC_RES_SUCCESS; }
/** * Run verification on a slot * * @param me CrosEc instance * @param region Region to run verification on * @return 0 if success or not applicable. Non-zero if verification failed. */ int cros_ec_efs_verify(struct udevice *dev, enum ec_flash_region region) { struct ec_params_efs_verify p; int rv; log_info("EFS: EC is verifying updated image...\n"); p.region = region; rv = ec_command(dev, EC_CMD_EFS_VERIFY, 0, &p, sizeof(p), NULL, 0); if (rv >= 0) { log_info("EFS: Verification success\n"); return 0; } if (rv == -EC_RES_INVALID_COMMAND) { log_info("EFS: EC doesn't support EFS_VERIFY command\n"); return 0; } log_info("EFS: Verification failed\n"); return rv; }
int ec_flash_read(uint8_t *buf, int offset, int size) { struct ec_params_flash_read p; int rv; int i; /* Read data in chunks */ for (i = 0; i < size; i += ec_max_insize) { p.offset = offset + i; p.size = MIN(size - i, ec_max_insize); rv = ec_command(EC_CMD_FLASH_READ, 0, &p, sizeof(p), ec_inbuf, p.size); if (rv < 0) { fprintf(stderr, "Read error at offset %d\n", i); return rv; } memcpy(buf + i, ec_inbuf, p.size); } return 0; }
static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev, struct ec_response_vboot_hash *hash) { struct ec_params_vboot_hash p; ulong start; start = get_timer(0); while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) { mdelay(50); /* Insert some reasonable delay */ p.cmd = EC_VBOOT_HASH_GET; if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), hash, sizeof(*hash)) < 0) return -1; if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) { debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__); return -EC_RES_TIMEOUT; } } return 0; }
static int cros_ec_handle_non_uhepi_cmd(struct udevice *dev, uint hcmd, uint action, uint64_t *value) { int ret = -1; struct ec_params_host_event_mask req; struct ec_response_host_event_mask rsp; if (hcmd == INVALID_HCMD) return ret; if (action != EC_HOST_EVENT_GET) req.mask = (uint32_t)*value; else *value = 0; ret = ec_command(dev, hcmd, 0, &req, sizeof(req), &rsp, sizeof(rsp)); if (action != EC_HOST_EVENT_GET) return ret; if (ret == 0) *value = rsp.mask; return ret; }