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:
committed by
Patrick Georgi
parent
fc0f5175fb
commit
60e6bf80db
@ -29,6 +29,30 @@
|
|||||||
#include "ec.h"
|
#include "ec.h"
|
||||||
#include "ec_commands.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)
|
static int google_chromeec_wait_ready(u16 port)
|
||||||
{
|
{
|
||||||
u8 ec_status = inb(port);
|
u8 ec_status = inb(port);
|
||||||
@ -51,7 +75,119 @@ static int google_chromeec_wait_ready(u16 port)
|
|||||||
return 0;
|
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;
|
struct ec_lpc_host_args args;
|
||||||
const u8 *d;
|
const u8 *d;
|
||||||
@ -134,7 +270,36 @@ int google_chromeec_command(struct chromeec_command *cec_command)
|
|||||||
return 0;
|
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__
|
#ifndef __SMM__
|
||||||
static void lpc_ec_init(struct device *dev)
|
static void lpc_ec_init(struct device *dev)
|
||||||
|
Reference in New Issue
Block a user