[coreboot-gerrit] Patch set updated for coreboot: 2be72f9 ec/google: Support Chrome EC protocol version 3.

Gabe Black (gabeblack@chromium.org) gerrit at coreboot.org
Wed Jul 10 11:36:36 CEST 2013


Gabe Black (gabeblack at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3750

-gerrit

commit 2be72f9fcb014975c2c6e78044cfde83d8378377
Author: Hung-Te Lin <hungte at chromium.org>
Date:   Sat Jun 22 11:18:39 2013 +0800

    ec/google: Support Chrome EC protocol version 3.
    
    Add the new Chrome EC protocol version 3 to Coreboot.
    
    Note, protocol version 3 is not applied on any bus implementations yet.
    LPC (x86) and I2C (arm/snow) are still using v2 protocol.  The first one to use
    v3 protocol will be SPI bus (arm/pit).  LPC / I2C will be updated to v3 only
    when they are ready to change.
    
    Change-Id: I3006435295fb509c6351afbb97de0fcedcb1d8c4
    Signed-off-by: Hung-Te Lin <hungte at chromium.org>
---
 src/ec/google/chromeec/crosec_proto.c | 224 +++++++++++++++++++++++++++++++++-
 src/ec/google/chromeec/ec.h           |   2 +-
 2 files changed, 223 insertions(+), 3 deletions(-)

diff --git a/src/ec/google/chromeec/crosec_proto.c b/src/ec/google/chromeec/crosec_proto.c
index 016de8d..42c7c2e 100644
--- a/src/ec/google/chromeec/crosec_proto.c
+++ b/src/ec/google/chromeec/crosec_proto.c
@@ -26,9 +26,229 @@
 #include "ec_commands.h"
 #include "ec_message.h"
 
+/* Common utilities */
+
+/* Dumps EC command / response data into debug output.
+ *
+ * @param name	Message prefix name.
+ * @param cmd	Command code, or -1 to ignore cmd message.
+ * @param data	Data buffer to print.
+ * @param len	Length of data.
+ */
+static void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data,
+			      int len)
+{
+	int i;
+
+	printk(BIOS_DEBUG, "%s: ", name);
+	if (cmd != -1)
+		printk(BIOS_DEBUG, "cmd=%#x: ", cmd);
+	for (i = 0; i < len; i++)
+		printk(BIOS_DEBUG, "%02x ", data[i]);
+	printk(BIOS_DEBUG, "\n");
+}
+
+/* Calculate a simple 8-bit checksum of a data block
+ *
+ * @param data	Data block to checksum
+ * @param size	Size of data block in bytes
+ * @return checksum value (0 to 255)
+ */
+static int cros_ec_calc_checksum(const uint8_t *data, int size)
+{
+	int csum, i;
+
+	for (i = csum = 0; i < size; i++)
+		csum += data[i];
+	return csum & 0xff;
+}
+
+/* Standard Chrome EC protocol, version 3 */
+
+struct ec_command_v3 {
+	struct ec_host_request header;
+	uint8_t data[MSG_BYTES];
+};
+
+struct ec_response_v3 {
+	struct ec_host_response header;
+	uint8_t data[MSG_BYTES];
+};
+
+/**
+ * Create a request packet for protocol version 3.
+ *
+ * @param cec_command	Command description.
+ * @param cmd		Packed command bit stream.
+ * @return packet size in bytes, or <0 if error.
+ */
+static int create_proto3_request(const struct chromeec_command *cec_command,
+				 struct ec_command_v3 *cmd)
+{
+	struct ec_host_request *rq = &cmd->header;
+	int out_bytes = cec_command->cmd_size_in + sizeof(*rq);
+
+	/* Fail if output size is too big */
+	if (out_bytes > sizeof(*cmd)) {
+		printk(BIOS_ERR, "%s: Cannot send %d bytes\n", __func__,
+		       cec_command->cmd_size_in);
+		return -EC_RES_REQUEST_TRUNCATED;
+	}
+
+	/* Fill in request packet */
+	rq->struct_version = EC_HOST_REQUEST_VERSION;
+	rq->checksum = 0;
+	rq->command = cec_command->cmd_code;
+	rq->command_version = cec_command->cmd_version;
+	rq->reserved = 0;
+	rq->data_len = cec_command->cmd_size_in;
+
+	/* Copy data after header */
+	memcpy(cmd->data, cec_command->cmd_data_in, cec_command->cmd_size_in);
+
+	/* Write checksum field so the entire packet sums to 0 */
+	rq->checksum = (uint8_t)(-cros_ec_calc_checksum(
+			(const uint8_t*)cmd, out_bytes));
+
+	cros_ec_dump_data("out", rq->command, (const uint8_t *)cmd, out_bytes);
+
+	/* Return size of request packet */
+	return out_bytes;
+}
+
+/**
+ * Prepare the device to receive a protocol version 3 response.
+ *
+ * @param cec_command	Command description.
+ * @param resp		Response buffer.
+ * @return maximum expected number of bytes in response, or <0 if error.
+ */
+static int prepare_proto3_response_buffer(
+		const struct chromeec_command *cec_command,
+		struct ec_response_v3 *resp)
+{
+	int in_bytes = cec_command->cmd_size_out + sizeof(resp->header);
+
+	/* Fail if input size is too big */
+	if (in_bytes > sizeof(*resp)) {
+		printk(BIOS_ERR, "%s: Cannot receive %d bytes\n", __func__,
+		       cec_command->cmd_size_out);
+		return -EC_RES_RESPONSE_TOO_BIG;
+	}
+
+	/* Return expected size of response packet */
+	return in_bytes;
+}
+
+/**
+ * Handle a protocol version 3 response packet.
+ *
+ * The packet must already be stored in the response buffer.
+ *
+ * @param resp		Response buffer.
+ * @param cec_command	Command structure to receive valid response.
+ * @return number of bytes of response data, or <0 if error
+ */
+static int handle_proto3_response(struct ec_response_v3 *resp,
+				  struct chromeec_command *cec_command)
+{
+	struct ec_host_response *rs = &resp->header;
+	int in_bytes;
+	int csum;
+
+	cros_ec_dump_data("in-header", -1, (const uint8_t*)rs, sizeof(*rs));
+
+	/* Check input data */
+	if (rs->struct_version != EC_HOST_RESPONSE_VERSION) {
+		printk(BIOS_ERR, "%s: EC response version mismatch\n", __func__);
+		return -EC_RES_INVALID_RESPONSE;
+	}
+
+	if (rs->reserved) {
+		printk(BIOS_ERR, "%s: EC response reserved != 0\n", __func__);
+		return -EC_RES_INVALID_RESPONSE;
+	}
+
+	if (rs->data_len > sizeof(resp->data) ||
+	    rs->data_len > cec_command->cmd_size_out) {
+		printk(BIOS_ERR, "%s: EC returned too much data\n", __func__);
+		return -EC_RES_RESPONSE_TOO_BIG;
+	}
+
+	cros_ec_dump_data("in-data", -1, resp->data, rs->data_len);
+
+	/* Update in_bytes to actual data size */
+	in_bytes = sizeof(*rs) + rs->data_len;
+
+	/* Verify checksum */
+	csum = cros_ec_calc_checksum((const uint8_t *)resp, in_bytes);
+	if (csum) {
+		printk(BIOS_ERR, "%s: EC response checksum invalid: 0x%02x\n",
+		       __func__, csum);
+		return -EC_RES_INVALID_CHECKSUM;
+	}
+
+	/* Return raw response. */
+	cec_command->cmd_code = rs->result;
+	cec_command->cmd_size_out = rs->data_len;
+	memcpy(cec_command->cmd_data_out, resp->data, rs->data_len);
+
+	/* Return error result, if any */
+	if (rs->result) {
+		printk(BIOS_ERR, "%s: EC response with error code: %d\n",
+		       __func__, rs->result);
+		return -(int)rs->result;
+	}
+
+	return rs->data_len;
+}
+
+static int send_command_proto3(struct chromeec_command *cec_command,
+			       crosec_io_t crosec_io, void *context)
+{
+	int out_bytes, in_bytes;
+	int rv;
+	struct ec_command_v3 cmd = { {0}, };
+	struct ec_response_v3 resp = { {0}, };
+
+	/* Create request packet */
+	out_bytes = create_proto3_request(cec_command, &cmd);
+	if (out_bytes < 0) {
+		return out_bytes;
+	}
+
+	/* Prepare response buffer */
+	in_bytes = prepare_proto3_response_buffer(cec_command, &resp);
+	if (in_bytes < 0) {
+		return in_bytes;
+	}
+
+	rv = crosec_io((uint8_t *)&cmd, out_bytes, (uint8_t *)&resp, in_bytes,
+		       context);
+	if (rv != 0) {
+		printk(BIOS_ERR, "%s: failed to complete I/O: Err = %#x.",
+		       __func__, rv >= 0 ? rv : -rv);
+		return -EC_RES_ERROR;
+	}
+
+	/* Process the response */
+	return handle_proto3_response(&resp, cec_command);
+}
+
+static int crosec_command_proto_v3(struct chromeec_command *cec_command,
+				   crosec_io_t crosec_io, void *context)
+{
+	int rv = send_command_proto3(cec_command, crosec_io, context);
+	if (rv < 0) {
+		cec_command->cmd_code = rv;
+		return 1;
+	}
+	return 0;
+}
+
 int crosec_command_proto(struct chromeec_command *cec_command,
 			 crosec_io_t crosec_io, void *context)
 {
-	// TODO(hungte) Add v3 protocol.
-	return -1;
+	// TODO(hungte) Detect and fallback to v2 if we need.
+	return crosec_command_proto_v3(cec_command, crosec_io, context);
 }
diff --git a/src/ec/google/chromeec/ec.h b/src/ec/google/chromeec/ec.h
index 13e9f23..356d2d2 100644
--- a/src/ec/google/chromeec/ec.h
+++ b/src/ec/google/chromeec/ec.h
@@ -53,7 +53,7 @@ int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode);
 
 /* internal structure to send a command to the EC and wait for response. */
 struct chromeec_command {
-	uint8_t     cmd_code;	  /* command code in, status out */
+	uint16_t    cmd_code;	  /* command code in, status out */
 	uint8_t     cmd_version;  /* command version */
 	const void* cmd_data_in;  /* command data, if any */
 	void*	    cmd_data_out; /* command response, if any */



More information about the coreboot-gerrit mailing list