diff options
author | Aaron Durbin <adurbin@chromium.org> | 2014-08-06 14:38:52 -0500 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2015-03-21 10:43:30 +0100 |
commit | aee78f0dbe3ee9984c8c1b8969a0a4b97c4e5d16 (patch) | |
tree | ffe863497e7912cc551325dfd8d6a97fd75e20ea | |
parent | 828272767d067cc215ff6c7dc93bd731a1a61765 (diff) |
chromeec: provide proto v3 over i2c support
Certain boards need to speak proto v3 over i2c. Leverage the
transport agnostic API to share the logic with other proto v3
impelementations.
BUG=chrome-os-partner:31148
BRANCH=None
TEST=Built and ran on ryu. Can talk to the EC successfully.
Change-Id: I1d0cd6907057af4ded3c4460193bbe1d897a1db7
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: cb9ac965ad04c9491f40fd9aa595176a28a467b3
Original-Change-Id: Ib699120fd232392e8caa0889c2bf40f4587a8a35
Original-Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/211139
Original-Reviewed-by: Stefan Reinauer <reinauer@google.com>
Original-Reviewed-by: Tom Warren <twarren@nvidia.com>
Original-Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Original-Tested-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: http://review.coreboot.org/8828
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
-rw-r--r-- | src/ec/google/chromeec/Kconfig | 7 | ||||
-rw-r--r-- | src/ec/google/chromeec/ec_i2c.c | 107 |
2 files changed, 114 insertions, 0 deletions
diff --git a/src/ec/google/chromeec/Kconfig b/src/ec/google/chromeec/Kconfig index cad1b487bd..bec12fb10a 100644 --- a/src/ec/google/chromeec/Kconfig +++ b/src/ec/google/chromeec/Kconfig @@ -19,6 +19,13 @@ config EC_GOOGLE_CHROMEEC_I2C_CHIP hex default 0x1e +config EC_GOOGLE_CHROMEEC_I2C_PROTO3 + depends on EC_GOOGLE_CHROMEEC_I2C + bool + default n + help + Use only proto3 for i2c EC communication. + config EC_GOOGLE_CHROMEEC_LPC depends on EC_GOOGLE_CHROMEEC && ARCH_X86 # Needs Plug-and-play. def_bool y diff --git a/src/ec/google/chromeec/ec_i2c.c b/src/ec/google/chromeec/ec_i2c.c index 551c3b9a87..03e2b365a1 100644 --- a/src/ec/google/chromeec/ec_i2c.c +++ b/src/ec/google/chromeec/ec_i2c.c @@ -27,6 +27,111 @@ #include "ec.h" #include "ec_commands.h" +#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_I2C_PROTO3) + +#define PROTO3_FRAMING_BYTES sizeof(uint32_t) +/* Just use the LPC host packet size to size the buffer. */ +#define PROTO3_MAX_PACKET_SIZE 268 + +struct proto3_i2c_buf { + uint8_t framing_bytes[PROTO3_FRAMING_BYTES]; + uint8_t data[PROTO3_MAX_PACKET_SIZE]; +} __attribute__((aligned(sizeof(uint32_t)))); + +static struct proto3_i2c_buf req_buf; +static struct proto3_i2c_buf resp_buf; + +enum { + CMD_INDEX, + RESP_INDEX, + SEGS_PER_CMD, +}; + +struct i2c_ec { + int bus; + struct i2c_seg segs[SEGS_PER_CMD]; +}; + +static struct i2c_ec ec_dev = { + .bus = CONFIG_EC_GOOGLE_CHROMEEC_I2C_BUS, + .segs[CMD_INDEX] = { + .read = 0, + .chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP, + /* Framing byte to be transferred prior to request. */ + .buf = &req_buf.framing_bytes[3], + }, + .segs[RESP_INDEX] = { + .read = 1, + .chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP, + /* return code and total length before full response. */ + .buf = &resp_buf.framing_bytes[2], + }, +}; + +void *crosec_get_buffer(size_t size, int req) +{ + struct proto3_i2c_buf *ib; + + if (size > PROTO3_MAX_PACKET_SIZE) { + printk(BIOS_DEBUG, "Proto v3 buffer request too large: %zu!\n", + size); + return NULL; + } + + if (req) + ib = &req_buf; + else + ib = &resp_buf; + + return &ib->data[0]; +} + +static int crosec_i2c_io(size_t req_size, size_t resp_size, void *context) +{ + struct i2c_ec *ec = context; + uint8_t ret_code; + size_t resp_len; + + if (req_size > PROTO3_MAX_PACKET_SIZE || + resp_size > PROTO3_MAX_PACKET_SIZE) + return -1; + + /* Place the framing byte and set size accordingly. */ + ec->segs[CMD_INDEX].len = req_size + 1; + ec->segs[CMD_INDEX].buf[0] = EC_COMMAND_PROTOCOL_3; + /* Return code and length returned prior to packet data. */ + ec->segs[RESP_INDEX].len = resp_size + 2; + + if (i2c_transfer(ec->bus, ec->segs, ARRAY_SIZE(ec->segs)) != 0) { + printk(BIOS_ERR, "%s: Cannot complete read from i2c-%d:%#x\n", + __func__, ec->bus, ec->segs[0].chip); + return -1; + } + + ret_code = ec->segs[RESP_INDEX].buf[0]; + resp_len = ec->segs[RESP_INDEX].buf[1]; + + if (ret_code != 0) { + printk(BIOS_ERR, "EC command returned 0x%x\n", ret_code); + return -1; + } + + if (resp_len > resp_size) { + printk(BIOS_ERR, "Response length mismatch %zu vs %zu\n", + resp_len, resp_size); + return -1; + } + + return 0; +} + +int google_chromeec_command(struct chromeec_command *cec_command) +{ + return crosec_command_proto(cec_command, crosec_i2c_io, &ec_dev); +} + +#else /* CONFIG_EC_GOOGLE_CHROMEEC_I2C_PROTO3 */ + /* Command (host->device) format for I2C: * uint8_t version, cmd, len, data[len], checksum; * @@ -151,6 +256,8 @@ int google_chromeec_command(struct chromeec_command *cec_command) return 0; } +#endif /* CONFIG_EC_GOOGLE_CHROMEEC_I2C_PROTO3 */ + #ifndef __PRE_RAM__ u8 google_chromeec_get_event(void) { |