Exemplo n.º 1
0
static int cros_ec_check_version(struct cros_ec_dev *dev)
{
	struct ec_params_hello req;
	struct ec_response_hello *resp;

	struct dm_cros_ec_ops *ops;
	int ret;

	ops = dm_cros_ec_get_ops(dev->dev);
	if (ops->check_version) {
		ret = ops->check_version(dev->dev);
		if (ret)
			return ret;
	}

	/*
	 * TODO([email protected]).
	 * There is a strange oddity here with the EC. We could just ignore
	 * the response, i.e. pass the last two parameters as NULL and 0.
	 * In this case we won't read back very many bytes from the EC.
	 * On the I2C bus the EC gets upset about this and will try to send
	 * the bytes anyway. This means that we will have to wait for that
	 * to complete before continuing with a new EC command.
	 *
	 * This problem is probably unique to the I2C bus.
	 *
	 * So for now, just read all the data anyway.
	 */

	/* Try sending a version 3 packet */
	dev->protocol_version = 3;
	req.in_data = 0;
	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
			     (uint8_t **)&resp, sizeof(*resp)) > 0) {
		return 0;
	}

	/* Try sending a version 2 packet */
	dev->protocol_version = 2;
	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
		       (uint8_t **)&resp, sizeof(*resp)) > 0) {
		return 0;
	}

	/*
	 * Fail if we're still here, since the EC doesn't understand any
	 * protcol version we speak.  Version 1 interface without command
	 * version is no longer supported, and we don't know about any new
	 * protocol versions.
	 */
	dev->protocol_version = 0;
	printf("%s: ERROR: old EC interface not supported\n", __func__);
	return -1;
}
Exemplo n.º 2
0
int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
		uint8_t flags)
{
	struct ec_params_reboot_ec p;

	p.cmd = cmd;
	p.flags = flags;

	if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0)
			< 0)
		return -1;

	if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
		/*
		 * EC reboot will take place immediately so delay to allow it
		 * to complete.  Note that some reboot types (EC_REBOOT_COLD)
		 * will reboot the AP as well, in which case we won't actually
		 * get to this point.
		 */
		/*
		 * TODO([email protected]): Would be nice if we had a
		 * better way to determine when the reboot is complete.  Could
		 * we poll a memory-mapped LPC value?
		 */
		udelay(50000);
	}

	return 0;
}
Exemplo n.º 3
0
int cros_ec_read_id(struct udevice *dev, char *id, int maxlen)
{
	struct ec_response_get_version *r;
	int ret;

	ret = ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
			       (uint8_t **)&r, sizeof(*r));
	if (ret != sizeof(*r)) {
		log_err("Got rc %d, expected %u\n", ret, (uint)sizeof(*r));
		return -1;
	}

	if (maxlen > (int)sizeof(r->version_string_ro))
		maxlen = sizeof(r->version_string_ro);

	switch (r->current_image) {
	case EC_IMAGE_RO:
		memcpy(id, r->version_string_ro, maxlen);
		break;
	case EC_IMAGE_RW:
		memcpy(id, r->version_string_rw, maxlen);
		break;
	default:
		log_err("Invalid EC image %d\n", r->current_image);
		return -1;
	}

	id[maxlen - 1] = '\0';
	return 0;
}
Exemplo n.º 4
0
int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen)
{
	struct ec_response_get_version *r;

	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
			(uint8_t **)&r, sizeof(*r)) != sizeof(*r))
		return -1;

	if (maxlen > (int)sizeof(r->version_string_ro))
		maxlen = sizeof(r->version_string_ro);

	switch (r->current_image) {
	case EC_IMAGE_RO:
		memcpy(id, r->version_string_ro, maxlen);
		break;
	case EC_IMAGE_RW:
		memcpy(id, r->version_string_rw, maxlen);
		break;
	default:
		return -1;
	}

	id[maxlen - 1] = '\0';
	return 0;
}
Exemplo n.º 5
0
int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp)
{
	if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0,
			(uint8_t **)strp, EC_PROTO2_MAX_PARAM_SIZE) < 0)
		return -1;

	return 0;
}
Exemplo n.º 6
0
int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
{
	struct ec_params_flash_erase p;

	p.offset = offset;
	p.size = size;
	return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p),
			NULL, 0);
}
Exemplo n.º 7
0
int cros_ec_read_version(struct cros_ec_dev *dev,
		       struct ec_response_get_version **versionp)
{
	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
			(uint8_t **)versionp, sizeof(**versionp))
			!= sizeof(**versionp))
		return -1;

	return 0;
}
Exemplo n.º 8
0
int cros_ec_read_current_image(struct cros_ec_dev *dev,
		enum ec_current_image *image)
{
	struct ec_response_get_version *r;

	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
			(uint8_t **)&r, sizeof(*r)) != sizeof(*r))
		return -1;

	*image = r->current_image;
	return 0;
}
Exemplo n.º 9
0
int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state)
{
	struct ec_params_ldo_set params;

	params.index = index;
	params.state = state;

	if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0, &params, sizeof(params),
			     NULL, 0))
		return -1;

	return 0;
}
Exemplo n.º 10
0
/**
 * Write a single block to the flash
 *
 * Write a block of data to 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 write for a particular region.
 *
 * Attempting to write to the region where the EC is currently running from
 * will result in an error.
 *
 * @param dev		CROS-EC device
 * @param data		Pointer to data buffer to write
 * @param offset	Offset within flash to write to.
 * @param size		Number of bytes to write
 * @return 0 if ok, -1 on error
 */
static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
		const uint8_t *data, uint32_t offset, uint32_t size)
{
	struct ec_params_flash_write p;

	p.offset = offset;
	p.size = size;
	assert(data && p.size <= EC_FLASH_WRITE_VER0_SIZE);
	memcpy(&p + 1, data, p.size);

	return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
			  &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1;
}
Exemplo n.º 11
0
int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
{
	struct ec_params_vbnvcontext p;
	int len;

	p.op = EC_VBNV_CONTEXT_OP_WRITE;
	memcpy(p.block, block, sizeof(p.block));

	len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
			&p, sizeof(p), NULL, 0);
	if (len < 0)
		return -1;

	return 0;
}
Exemplo n.º 12
0
int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
{
	struct ec_params_ldo_get params;
	struct ec_response_ldo_get *resp;

	params.index = index;

	if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
		       &params, sizeof(params),
		       (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
		return -1;

	*state = resp->state;

	return 0;
}
Exemplo n.º 13
0
int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events)
{
	struct ec_params_host_event_mask params;

	params.mask = events;

	/*
	 * Use the B copy of the event flags, so it affects the data returned
	 * by cros_ec_get_host_events().
	 */
	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0,
		       &params, sizeof(params), NULL, 0) < 0)
		return -1;

	return 0;
}
Exemplo n.º 14
0
int cros_ec_write_nvdata(struct udevice *dev, const 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_WRITE;
	memcpy(p.block, block, size);

	len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
			&p, sizeof(uint32_t) + size, NULL, 0);
	if (len < 0)
		return -1;

	return 0;
}
Exemplo n.º 15
0
int cros_ec_test(struct cros_ec_dev *dev)
{
	struct ec_params_hello req;
	struct ec_response_hello *resp;

	req.in_data = 0x12345678;
	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
		printf("ec_command_inptr() returned error\n");
		return -1;
	}
	if (resp->out_data != req.in_data + 0x01020304) {
		printf("Received invalid handshake %x\n", resp->out_data);
		return -1;
	}

	return 0;
}
Exemplo n.º 16
0
int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr)
{
	struct ec_response_host_event_mask *resp;

	/*
	 * Use the B copy of the event flags, because the main copy is already
	 * used by ACPI/SMI.
	 */
	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0,
		       (uint8_t **)&resp, sizeof(*resp)) < (int)sizeof(*resp))
		return -1;

	if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID))
		return -1;

	*events_ptr = resp->mask;
	return 0;
}
Exemplo n.º 17
0
int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
		      uint32_t *offset, uint32_t *size)
{
	struct ec_params_flash_region_info p;
	struct ec_response_flash_region_info *r;
	int ret;

	p.region = region;
	ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO,
			 EC_VER_FLASH_REGION_INFO,
			 &p, sizeof(p), (uint8_t **)&r, sizeof(*r));
	if (ret != sizeof(*r))
		return -1;

	if (offset)
		*offset = r->offset;
	if (size)
		*size = r->size;

	return 0;
}
Exemplo n.º 18
0
/**
 * Write a single block to the flash
 *
 * Write a block of data to 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 write for a particular region.
 *
 * Attempting to write to the region where the EC is currently running from
 * will result in an error.
 *
 * @param dev		CROS-EC device
 * @param data		Pointer to data buffer to write
 * @param offset	Offset within flash to write to.
 * @param size		Number of bytes to write
 * @return 0 if ok, -1 on error
 */
static int cros_ec_flash_write_block(struct udevice *dev, const uint8_t *data,
				     uint32_t offset, uint32_t size)
{
	struct ec_params_flash_write *p;
	int ret;

	p = malloc(sizeof(*p) + size);
	if (!p)
		return -ENOMEM;

	p->offset = offset;
	p->size = size;
	assert(data && p->size <= EC_FLASH_WRITE_VER0_SIZE);
	memcpy(p + 1, data, p->size);

	ret = ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
			  p, sizeof(*p) + size, NULL, 0) >= 0 ? 0 : -1;

	free(p);

	return ret;
}
Exemplo n.º 19
0
/**
 * Send a command to the CROS-EC device and return the reply.
 *
 * The device's internal input/output buffers are used.
 *
 * @param dev		CROS-EC device
 * @param cmd		Command to send (EC_CMD_...)
 * @param cmd_version	Version of command to send (EC_VER_...)
 * @param dout          Output data (may be NULL If dout_len=0)
 * @param dout_len      Size of output data in bytes
 * @param din           Response data (may be NULL If din_len=0).
 *			It not NULL, it is a place for ec_command() to copy the
 *      data to.
 * @param din_len       Maximum size of response in bytes
 * @return number of bytes in response, or -ve on error
 */
static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
		      const void *dout, int dout_len,
		      void *din, int din_len)
{
	uint8_t *in_buffer;
	int len;

	assert((din_len == 0) || din);
	len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len,
			&in_buffer, din_len);
	if (len > 0) {
		/*
		 * If we were asked to put it somewhere, do so, otherwise just
		 * disregard the result.
		 */
		if (din && in_buffer) {
			assert(len <= din_len);
			memmove(din, in_buffer, len);
		}
	}
	return len;
}
Exemplo n.º 20
0
static int cros_ec_invalidate_hash(struct cros_ec_dev *dev)
{
	struct ec_params_vboot_hash p;
	struct ec_response_vboot_hash *hash;

	/* We don't have an explict command for the EC to discard its current
	 * hash value, so we'll just tell it to calculate one that we know is
	 * wrong (we claim that hashing zero bytes is always invalid).
	 */
	p.cmd = EC_VBOOT_HASH_RECALC;
	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
	p.nonce_size = 0;
	p.offset = 0;
	p.size = 0;

	debug("%s:\n", __func__);

	if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
		       (uint8_t **)&hash, sizeof(*hash)) < 0)
		return -1;

	/* No need to wait for it to finish */
	return 0;
}