[coreboot-gerrit] New patch to review for coreboot: 501142a chromeec: Add support for v3 commands on LPC

Stefan Reinauer (stefan.reinauer@coreboot.org) gerrit at coreboot.org
Wed Apr 1 22:52:36 CEST 2015


Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9203

-gerrit

commit 501142ae790d6e272f9d44a144377edd60bda21e
Author: Duncan Laurie <dlaurie at chromium.org>
Date:   Thu Sep 18 12:51:07 2014 -0700

    chromeec: Add support for v3 commands on LPC
    
    In order to talk to the PD controller with a passthru command
    coreboot needs to be able to use v3 commands.
    
    The command version is automatically detected based on the
    advertized flags from the EC.
    
    BUG=chrome-os-partner:30079
    BRANCH=none
    TEST=boot on samus EVT
    
    Change-Id: I032eb185d80d5b68c82609910045e21d4521afcc
    Signed-off-by: Stefan Reinauer <reinauer at chromium.org>
    Original-Commit-Id: 4f664b22645f0def87a73e9255297b3edccf436e
    Original-Change-Id: I94ace7741c9cd592921625fb793787247a5ca2aa
    Original-Signed-off-by: Duncan Laurie <dlaurie at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/218902
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
---
 src/ec/google/chromeec/ec_lpc.c | 169 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 167 insertions(+), 2 deletions(-)

diff --git a/src/ec/google/chromeec/ec_lpc.c b/src/ec/google/chromeec/ec_lpc.c
index 5344716..ed0b76a 100644
--- a/src/ec/google/chromeec/ec_lpc.c
+++ b/src/ec/google/chromeec/ec_lpc.c
@@ -29,6 +29,30 @@
 #include "ec.h"
 #include "ec_commands.h"
 
+static int google_chromeec_command_version(void)
+{
+	u8 id1, id2, flags;
+
+	id1 = inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID);
+	id2 = inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1);
+	flags = inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS);
+
+	if (id1 != 'E' || id2 != 'C') {
+		printk(BIOS_ERR, "Missing Chromium EC memory map.\n");
+		return -1;
+	}
+
+	if (flags & EC_HOST_CMD_FLAG_VERSION_3) {
+		return EC_HOST_CMD_FLAG_VERSION_3;
+	} else if (flags & EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED) {
+		return EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED;
+	} else {
+		printk(BIOS_ERR,
+		       "Chromium EC command version unsupported\n");
+		return -1;
+	}
+}
+
 static int google_chromeec_wait_ready(u16 port)
 {
 	u8 ec_status = inb(port);
@@ -51,7 +75,119 @@ static int google_chromeec_wait_ready(u16 port)
 	return 0;
 }
 
-int google_chromeec_command(struct chromeec_command *cec_command)
+static int google_chromeec_command_v3(struct chromeec_command *cec_command)
+{
+	struct ec_host_request rq;
+	struct ec_host_response rs;
+	const u8 *d;
+	u8 *dout;
+	int csum = 0;
+	int i;
+
+	if (cec_command->cmd_size_in + sizeof(rq) > EC_LPC_HOST_PACKET_SIZE) {
+		printk(BIOS_ERR, "EC cannot send %d bytes\n",
+		       cec_command->cmd_size_in + sizeof(rq));
+		return -1;
+	}
+
+	if (cec_command->cmd_size_out > EC_LPC_HOST_PACKET_SIZE) {
+		printk(BIOS_ERR, "EC cannot receive %d bytes\n",
+		       cec_command->cmd_size_out);
+		return -1;
+	}
+
+	if (google_chromeec_wait_ready(EC_LPC_ADDR_HOST_CMD)) {
+		printk(BIOS_ERR, "Timeout waiting for EC start command %d!\n",
+		       cec_command->cmd_code);
+		return -1;
+	}
+
+	/* Fill in request packet */
+	rq.struct_version = EC_HOST_REQUEST_VERSION;
+	rq.checksum = 0;
+	rq.command = cec_command->cmd_code |
+		EC_CMD_PASSTHRU_OFFSET(cec_command->cmd_dev_index);
+	rq.command_version = cec_command->cmd_version;
+	rq.reserved = 0;
+	rq.data_len = cec_command->cmd_size_in;
+
+	/* Copy data and start checksum */
+	for (i = 0, d = (const u8 *)cec_command->cmd_data_in;
+	     i < cec_command->cmd_size_in; i++, d++) {
+		outb(*d, EC_LPC_ADDR_HOST_PACKET + sizeof(rq) + i);
+		csum += *d;
+	}
+
+	/* Finish checksum */
+	for (i = 0, d = (const u8 *)&rq; i < sizeof(rq); i++, d++)
+		csum += *d;
+
+	/* Write checksum field so the entire packet sums to 0 */
+	rq.checksum = (u8)(-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 (google_chromeec_wait_ready(EC_LPC_ADDR_HOST_CMD)) {
+		printk(BIOS_ERR, "Timeout waiting for EC process command %d!\n",
+		       cec_command->cmd_code);
+		return -1;
+	}
+
+	/* Check result */
+	cec_command->cmd_code = inb(EC_LPC_ADDR_HOST_DATA);
+	if (cec_command->cmd_code) {
+		printk(BIOS_ERR, "EC returned error result code %d\n",
+			cec_command->cmd_code);
+		return -i;
+	}
+
+	/* Read back response header and start checksum */
+	csum = 0;
+	for (i = 0, dout = (u8 *)&rs; i < sizeof(rs); i++, dout++) {
+		*dout = inb(EC_LPC_ADDR_HOST_PACKET + i);
+		csum += *dout;
+	}
+
+	if (rs.struct_version != EC_HOST_RESPONSE_VERSION) {
+		printk(BIOS_ERR, "EC response version mismatch (%d != %d)\n",
+		       rs.struct_version, EC_HOST_RESPONSE_VERSION);
+		return -1;
+	}
+
+	if (rs.reserved) {
+		printk(BIOS_ERR, "EC response reserved is %d, should be 0\n",
+			rs.reserved);
+		return -1;
+	}
+
+	if (rs.data_len > cec_command->cmd_size_out) {
+		printk(BIOS_ERR, "EC returned too much data (%d > %d)\n",
+		       rs.data_len, cec_command->cmd_size_out);
+		return -1;
+	}
+
+	/* Read back data and update checksum */
+	for (i = 0, dout = (uint8_t *)cec_command->cmd_data_out;
+	     i < rs.data_len; i++, dout++) {
+		*dout = inb(EC_LPC_ADDR_HOST_PACKET + sizeof(rs) + i);
+		csum += *dout;
+	}
+
+	/* Verify checksum */
+	if ((u8)csum) {
+		printk(BIOS_ERR, "EC response has invalid checksum\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int google_chromeec_command_v1(struct chromeec_command *cec_command)
 {
 	struct ec_lpc_host_args args;
 	const u8 *d;
@@ -134,7 +270,36 @@ int google_chromeec_command(struct chromeec_command *cec_command)
 	return 0;
 }
 
-#ifndef __PRE_RAM__
+#ifdef __PRE_RAM__
+
+int google_chromeec_command(struct chromeec_command *cec_command)
+{
+	switch (google_chromeec_command_version()) {
+	case EC_HOST_CMD_FLAG_VERSION_3:
+		return google_chromeec_command_v3(cec_command);
+	case EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED:
+		return google_chromeec_command_v1(cec_command);
+	}
+	return -1;
+}
+
+#else /* !__PRE_RAM__ */
+
+int google_chromeec_command(struct chromeec_command *cec_command)
+{
+	static int command_version = 0;
+
+	if (command_version <= 0)
+		command_version = google_chromeec_command_version();
+
+	switch (command_version) {
+	case EC_HOST_CMD_FLAG_VERSION_3:
+		return google_chromeec_command_v3(cec_command);
+	case EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED:
+		return google_chromeec_command_v1(cec_command);
+	}
+	return -1;
+}
 
 #ifndef __SMM__
 static void lpc_ec_init(struct device *dev)



More information about the coreboot-gerrit mailing list