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@chromium.org> Original-Commit-Id: 4f664b22645f0def87a73e9255297b3edccf436e Original-Change-Id: I94ace7741c9cd592921625fb793787247a5ca2aa Original-Signed-off-by: Duncan Laurie <dlaurie@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/218902 Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/9203 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
parent
fc0f5175fb
commit
60e6bf80db
|
@ -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 %ld 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)
|
||||
|
|
Loading…
Reference in New Issue