From bff14cac0b17217a6be02924d109e58b3aaa50b1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 15 Jul 2012 03:03:55 +0100 Subject: i2c: Support command version numbers Currently, I2C commands look like this: Input: cmd8 [params bytes] checksum Output: response8 [response_ptr bytes] checksum Use a prefix byte of (0xDC + cmd_version) to indicate the command version. This is compatible with the existing protocol, since there are no host commands in the range 0xDC-0xFB. If the first byte of the from-host data is 0x00-0xDB, it's a version 0 command. There is no change to the output format, since the EC needs to hand back a response which matches the version requested by the host. New input: (0xDC+ver8) cmd8 paramlen8 [params bytes] checksum New output: response8 responselen8 [response_ptr bytes] checksum If the host gets a response of EC_RES_INVALID_COMMAND, it knows it's talking to an old EC, and at most version 0 of the command is supported. BUG=chrome-os-partner:11317 TEST=manual and a bit ad-hoc: (note, this testing is not completed yet, so far only snow is tested) Check that snow and link still process commands correctly over I2C from U-Boot. SMDK5250 # mkbp test Old interface: New interface: Test passed Change-Id: I1c21f2b036091e9122b4f980ca5f5af34f7fc070 Signed-off-by: Simon Glass Reviewed-on: https://gerrit.chromium.org/gerrit/27470 --- chip/stm32/i2c.c | 59 +++++++++++++++++++++++++++++++++++++------------- include/ec_commands.h | 12 ++++++++++ include/host_command.h | 1 + 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index 31c5174c55..7e7bafefc6 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -41,8 +41,8 @@ static uint16_t i2c_sr1[NUM_PORTS]; static struct mutex i2c_mutex; -/* buffer for host commands (including error code and checksum) */ -static uint8_t host_buffer[EC_HOST_PARAM_SIZE + 2]; +/* buffer for host commands (including version, error code and checksum) */ +static uint8_t host_buffer[EC_HOST_PARAM_SIZE + 4]; static struct host_cmd_handler_args host_cmd_args; /* current position in host buffer for reception */ @@ -127,10 +127,14 @@ static void i2c_send_response(struct host_cmd_handler_args *args) const uint8_t *data = args->response; int size = args->response_size; uint8_t *out = host_buffer; - int sum, i; + int sum = 0, i; *out++ = args->result; - for (i = 0, sum = 0; i < size; i++, data++, out++) { + if (!args->i2c_old_response) { + *out++ = size; + sum = args->result + size; + } + for (i = 0; i < size; i++, data++, out++) { if (data != out) *out = *data; sum += *data; @@ -144,18 +148,43 @@ static void i2c_send_response(struct host_cmd_handler_args *args) /* Process the command in the i2c host buffer */ static void i2c_process_command(void) { + struct host_cmd_handler_args *args = &host_cmd_args; + char *buff = host_buffer; + + args->command = *buff; + args->result = EC_RES_SUCCESS; + if (args->command >= EC_CMD_VERSION0) { + int csum, i; + + /* Read version and data size */ + args->version = args->command - EC_CMD_VERSION0; + args->command = buff[1]; + args->params_size = buff[2]; + + /* Verify checksum */ + for (csum = i = 0; i < args->params_size + 3; i++) + csum += buff[i]; + if ((uint8_t)csum != buff[i]) + args->result = EC_RES_INVALID_CHECKSUM; + + buff += 3; + args->i2c_old_response = 0; + } else { + /* Old style command */ + args->version = 0; + args->params_size = EC_HOST_PARAM_SIZE; /* unknown */ + buff++; + args->i2c_old_response = 1; + } + /* we have an available command : execute it */ - host_cmd_args.command = host_buffer[0]; - host_cmd_args.result = EC_RES_SUCCESS; - host_cmd_args.send_response = i2c_send_response; - host_cmd_args.version = 0; - host_cmd_args.params = host_buffer + 1; - host_cmd_args.params_size = EC_HOST_PARAM_SIZE; - /* skip room for error code */ - host_cmd_args.response = host_buffer + 1; - host_cmd_args.response_max = EC_HOST_PARAM_SIZE; - host_cmd_args.response_size = 0; - host_command_received(&host_cmd_args); + args->send_response = i2c_send_response; + args->params = buff; + /* skip room for error code, arglen */ + args->response = host_buffer + 2; + args->response_max = EC_HOST_PARAM_SIZE; + args->response_size = 0; + host_command_received(args); } static void i2c_event_handler(int port) diff --git a/include/ec_commands.h b/include/ec_commands.h index 6c64aeef1d..b102c0bd3c 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -926,6 +926,18 @@ struct ec_params_reboot_ec { */ #define EC_CMD_REBOOT 0xd1 /* Think "die" */ +/* + * This header byte on a command indicate version 0. Any header byte less + * than this means that we are talking to an old EC which doesn't support + * versioning. In that case, we assume version 0. + * + * Header bytes greater than this indicate a later version. For example, + * EC_CMD_VERSION0 + 1 means we are using version 1. + * + * The old EC interface must not use commands 0dc or higher. + */ +#define EC_CMD_VERSION0 0xdc + #endif /* !__ACPI__ */ #endif /* __CROS_EC_COMMANDS_H */ diff --git a/include/host_command.h b/include/host_command.h index a88761a6e2..135f493737 100644 --- a/include/host_command.h +++ b/include/host_command.h @@ -22,6 +22,7 @@ struct host_cmd_handler_args { uint8_t command; /* Command (e.g., EC_CMD_FLASH_GET_INFO) */ uint8_t version; /* Version of command (0-31) */ uint8_t params_size; /* Size of input parameters in bytes */ + uint8_t i2c_old_response; /* (for I2C) send an old-style response */ const uint8_t *params; /* Input parameters */ /* * Pointer to output response data buffer. On input to the handler, -- cgit v1.2.1