summaryrefslogtreecommitdiff
path: root/util/comm-lpc.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-06-13 20:18:14 -0700
committerChromeBot <chrome-bot@google.com>2013-06-20 13:55:11 -0700
commite74e60c4651111a66380d99683ecd5cf9d7dbfb2 (patch)
tree6c6b5e18a1b41d0a70e5b83c86262909d993a824 /util/comm-lpc.c
parent4d4facda912767215d485bc83ddfa7ef9c060c2e (diff)
downloadchrome-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.c114
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;
}