ec/google/chromeec: Add minimum delay between SPI CS assertions
Some Chrome OS ECs require a small amount of time after a SPI transaction to reset their controllers before they can service the next CS assertion. The kernel and depthcharge have always enforced a 200us minimum delay for this... coreboot should've done the same. BRANCH=gru BUG=chrome-os-partner:58046 TEST=Booted Kevin in recovery mode, confirmed that recovery events got logged with correct timestamps in eventlog. Change-Id: I32ec343f3293ac93729d3e6e2f43d7605a396cdb Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: b9e4696533d4318ae7c8715b71ab963d8897c16c Original-Change-Id: I6a7baf7859d5d50e299495d118e7890dcaa2c1b0 Original-Signed-off-by: Julius Werner <jwerner@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/392206 Original-Tested-by: Shawn N <shawnn@chromium.org> Original-Reviewed-by: Shawn N <shawnn@chromium.org> Reviewed-on: https://review.coreboot.org/16885 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
parent
e06a1b895c
commit
93b51e7ac9
|
@ -20,6 +20,11 @@
|
||||||
#include <spi-generic.h>
|
#include <spi-generic.h>
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
|
|
||||||
|
/* This is assuming that this driver is not used on x86. If that changes, this
|
||||||
|
might need to become a CAR_GLOBAL or maybe even more complicated. */
|
||||||
|
static struct stopwatch cs_cooldown_sw;
|
||||||
|
static const long cs_cooldown_us = 200;
|
||||||
|
|
||||||
static const uint8_t EcFramingByte = 0xec;
|
static const uint8_t EcFramingByte = 0xec;
|
||||||
|
|
||||||
#define PROTO3_MAX_PACKET_SIZE 268
|
#define PROTO3_MAX_PACKET_SIZE 268
|
||||||
|
@ -44,7 +49,10 @@ void *crosec_get_buffer(size_t size, int req)
|
||||||
static int crosec_spi_io(size_t req_size, size_t resp_size, void *context)
|
static int crosec_spi_io(size_t req_size, size_t resp_size, void *context)
|
||||||
{
|
{
|
||||||
struct spi_slave *slave = (struct spi_slave *)context;
|
struct spi_slave *slave = (struct spi_slave *)context;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
while (!stopwatch_expired(&cs_cooldown_sw))
|
||||||
|
/* Wait minimum delay between CS assertions. */;
|
||||||
spi_claim_bus(slave);
|
spi_claim_bus(slave);
|
||||||
|
|
||||||
/* Allow EC to ramp up clock after being awaken.
|
/* Allow EC to ramp up clock after being awaken.
|
||||||
|
@ -53,8 +61,8 @@ static int crosec_spi_io(size_t req_size, size_t resp_size, void *context)
|
||||||
|
|
||||||
if (spi_xfer(slave, req_buf, req_size, NULL, 0)) {
|
if (spi_xfer(slave, req_buf, req_size, NULL, 0)) {
|
||||||
printk(BIOS_ERR, "%s: Failed to send request.\n", __func__);
|
printk(BIOS_ERR, "%s: Failed to send request.\n", __func__);
|
||||||
spi_release_bus(slave);
|
ret = -1;
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
@ -65,8 +73,8 @@ static int crosec_spi_io(size_t req_size, size_t resp_size, void *context)
|
||||||
if (spi_xfer(slave, NULL, 0, &byte, sizeof(byte))) {
|
if (spi_xfer(slave, NULL, 0, &byte, sizeof(byte))) {
|
||||||
printk(BIOS_ERR, "%s: Failed to receive byte.\n",
|
printk(BIOS_ERR, "%s: Failed to receive byte.\n",
|
||||||
__func__);
|
__func__);
|
||||||
spi_release_bus(slave);
|
ret = -1;
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
if (byte == EcFramingByte)
|
if (byte == EcFramingByte)
|
||||||
break;
|
break;
|
||||||
|
@ -75,28 +83,30 @@ static int crosec_spi_io(size_t req_size, size_t resp_size, void *context)
|
||||||
printk(BIOS_ERR,
|
printk(BIOS_ERR,
|
||||||
"%s: Timeout waiting for framing byte.\n",
|
"%s: Timeout waiting for framing byte.\n",
|
||||||
__func__);
|
__func__);
|
||||||
spi_release_bus(slave);
|
ret = -1;
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spi_xfer(slave, NULL, 0, resp_buf, resp_size)) {
|
if (spi_xfer(slave, NULL, 0, resp_buf, resp_size)) {
|
||||||
printk(BIOS_ERR, "%s: Failed to receive response.\n", __func__);
|
printk(BIOS_ERR, "%s: Failed to receive response.\n", __func__);
|
||||||
spi_release_bus(slave);
|
ret = -1;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
spi_release_bus(slave);
|
spi_release_bus(slave);
|
||||||
|
stopwatch_init_usecs_expire(&cs_cooldown_sw, cs_cooldown_us);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int google_chromeec_command(struct chromeec_command *cec_command)
|
int google_chromeec_command(struct chromeec_command *cec_command)
|
||||||
{
|
{
|
||||||
static struct spi_slave *slave = NULL;
|
static struct spi_slave *slave = NULL;
|
||||||
if (!slave)
|
if (!slave) {
|
||||||
slave = spi_setup_slave(CONFIG_EC_GOOGLE_CHROMEEC_SPI_BUS,
|
slave = spi_setup_slave(CONFIG_EC_GOOGLE_CHROMEEC_SPI_BUS,
|
||||||
CONFIG_EC_GOOGLE_CHROMEEC_SPI_CHIP);
|
CONFIG_EC_GOOGLE_CHROMEEC_SPI_CHIP);
|
||||||
|
stopwatch_init(&cs_cooldown_sw);
|
||||||
|
}
|
||||||
return crosec_command_proto(cec_command, crosec_spi_io, slave);
|
return crosec_command_proto(cec_command, crosec_spi_io, slave);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue