diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-06-13 20:18:14 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-06-20 13:55:11 -0700 |
commit | e74e60c4651111a66380d99683ecd5cf9d7dbfb2 (patch) | |
tree | 6c6b5e18a1b41d0a70e5b83c86262909d993a824 /util/comm-lpc.c | |
parent | 4d4facda912767215d485bc83ddfa7ef9c060c2e (diff) | |
download | chrome-ec-e74e60c4651111a66380d99683ecd5cf9d7dbfb2.tar.gz |
Refactor host command interface to support version 3 packets
This will fix EC flash commands on pit, once the host side (u-boot and
cros_ec driver) are upgraded to match.
This change is backwards-compatible the EC still supports the existing
version 2 protocols for talking to existing AP/kernel/ectool.
Once the AP-side supports version 3 for SPI (and existing systems are
upgraded), we will remove older SPI support since we haven't shipped a
product which uses SPI.
BUG=chrome-os-partner:20257
BRANCH=none
TEST=disable cros_ec driver support in ectool; 'ectool hello' works on link
And with an old ectool which predates this CL, 'ectool hello' also works.
On pit, from u-boot prompt, 'crosec test' and 'crosec version' work, and
keyboard works.
Change-Id: I01f193e316e9aa442fe50d632dc8a4681723e282
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/58908
Reviewed-by: Simon Glass <sjg@chromium.org>
Commit-Queue: Doug Anderson <dianders@chromium.org>
Diffstat (limited to 'util/comm-lpc.c')
-rw-r--r-- | util/comm-lpc.c | 114 |
1 files changed, 108 insertions, 6 deletions
diff --git a/util/comm-lpc.c b/util/comm-lpc.c index 3548f4eb29..c6ddee93c5 100644 --- a/util/comm-lpc.c +++ b/util/comm-lpc.c @@ -126,6 +126,99 @@ static int ec_command_lpc(int command, int version, return args.data_size; } +static int ec_command_lpc_3(int command, int version, + const void *outdata, int outsize, + void *indata, int insize) +{ + struct ec_host_request rq; + struct ec_host_response rs; + const uint8_t *d; + uint8_t *dout; + int csum = 0; + int i; + + /* Fail if output size is too big */ + if (outsize + sizeof(rq) > EC_HOST_PACKET_SIZE) + return -EC_RES_REQUEST_TRUNCATED; + + /* Fill in request packet */ + /* TODO: this should be common to all protocols */ + rq.struct_version = EC_HOST_REQUEST_VERSION; + rq.checksum = 0; + rq.command = command; + rq.command_version = version; + rq.reserved = 0; + rq.data_len = outsize; + + /* Copy data and start checksum */ + for (i = 0, d = (const uint8_t *)outdata; i < outsize; i++, d++) { + outb(*d, EC_LPC_ADDR_HOST_PACKET + sizeof(rq) + i); + csum += *d; + } + + /* Finish checksum */ + for (i = 0, d = (const uint8_t *)&rq; i < sizeof(rq); i++, d++) + csum += *d; + + /* Write checksum field so the entire packet sums to 0 */ + rq.checksum = (uint8_t)(-csum); + + /* Copy header */ + for (i = 0, d = (const uint8_t *)&rq; i < sizeof(rq); i++, d++) + outb(*d, EC_LPC_ADDR_HOST_PACKET + i); + + /* Start the command */ + outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); + + if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, 1000000)) { + fprintf(stderr, "Timeout waiting for EC response\n"); + return -EC_RES_ERROR; + } + + /* Check result */ + i = inb(EC_LPC_ADDR_HOST_DATA); + if (i) { + fprintf(stderr, "EC returned error result code %d\n", i); + return -i; + } + + /* Read back response header and start checksum */ + csum = 0; + for (i = 0, dout = (uint8_t *)&rs; i < sizeof(rs); i++, dout++) { + *dout = inb(EC_LPC_ADDR_HOST_PACKET + i); + csum += *dout; + } + + if (rs.struct_version != EC_HOST_RESPONSE_VERSION) { + fprintf(stderr, "EC response version mismatch\n"); + return -EC_RES_INVALID_RESPONSE; + } + + if (rs.reserved) { + fprintf(stderr, "EC response reserved != 0\n"); + return -EC_RES_INVALID_RESPONSE; + } + + if (rs.data_len > insize) { + fprintf(stderr, "EC returned too much data\n"); + return -EC_RES_RESPONSE_TOO_BIG; + } + + /* Read back data and update checksum */ + for (i = 0, dout = (uint8_t *)indata; i < rs.data_len; i++, dout++) { + *dout = inb(EC_LPC_ADDR_HOST_PACKET + sizeof(rs) + i); + csum += *dout; + } + + /* Verify checksum */ + if ((uint8_t)csum) { + fprintf(stderr, "EC response has invalid checksum\n"); + return -EC_RES_INVALID_CHECKSUM; + } + + /* Return actual amount of data received */ + return rs.data_len; +} static int ec_readmem_lpc(int offset, int bytes, void *dest) { @@ -194,15 +287,24 @@ int comm_init_lpc(void) * in args when it responds. */ if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E' || - inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C' || - !(inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS) & - EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) { - fprintf(stderr, "EC doesn't support command args.\n"); + inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C') { + fprintf(stderr, "Missing Chromium EC memory map.\n"); + return -5; + } + + /* Check which command version we'll use */ + i = inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS); + + if (i & EC_HOST_CMD_FLAG_VERSION_3) { + ec_command = ec_command_lpc_3; + } else if (i & EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED) { + ec_command = ec_command_lpc; + } else { + fprintf(stderr, "EC doesn't support protocols we need.\n"); return -5; } - /* Okay, this works */ - ec_command = ec_command_lpc; + /* Either one supports reading mapped memory directly */ ec_readmem = ec_readmem_lpc; return 0; } |