diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2017-11-03 15:03:30 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-11-08 03:12:23 -0800 |
commit | 753247a659874a4bcbd206aa76caba23ebcf57b9 (patch) | |
tree | 146b686bcb22594522c07838cf01e976eb247492 | |
parent | e4579a29905dc08e4a6ed6156363b64bd03c5be3 (diff) | |
download | chrome-ec-753247a659874a4bcbd206aa76caba23ebcf57b9.tar.gz |
g: handle delayed processing of the 'wake' pulses
Sometimes the AP will generate a short 'wake' pulse on the SPS CS line
just in case the chip is in the sleep state. This pulse is supposed to
wake up the chip and prepare it to process the actual SPS transaction
which follows the wake pulse in 100 us.
It turns out that under certain conditions it takes the Cr50 longer
than 100 us to react to the wake pulse, for instance when it writing
into flash which is in the same bank the code is running from, there
is no way to avoid stalling in this case.
What happens then is that the 'CS deasserted' interrupt for the wake
pulse comes while the actual SPS transaction is in progress. In this
case when processing the CS deassertion interrupt the Cr50 should not
consider it an end of a transaction, but just ignore it making sure
that the next CS deassertion still would trigger an interrupt.
BRANCH=none
BUG=b:68012381
TEST=verified that this patch helps the AP firmware test case which
was often failing due to TPM getting out of sync.
Change-Id: I412459552f4b2d13cd72800c1af7d583226e8466
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/754505
-rw-r--r-- | chip/g/sps.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/chip/g/sps.c b/chip/g/sps.c index d6d23e1d03..76b4d4d462 100644 --- a/chip/g/sps.c +++ b/chip/g/sps.c @@ -165,6 +165,15 @@ int sps_transmit(uint8_t *data, size_t data_size) return bytes_sent; } +static int sps_cs_asserted(void) +{ + /* + * Read the current value on the SPS CS line and return the iversion + * of it (CS is active low). + */ + return !GREAD_FIELD(SPS, VAL, CSB); +} + /** Configure the data transmission format * * @param mode Clock polarity and phase mode (0 - 3) @@ -185,7 +194,7 @@ static void sps_configure(enum sps_mode mode, enum spi_clock_mode clk_mode, /* xfer 0xff when tx fifo is empty */ GREG32(SPS, DUMMY_WORD) = GC_SPS_DUMMY_WORD_DEFAULT; - if (!GREAD_FIELD(SPS, VAL, CSB)) { + if (sps_cs_asserted()) { /* * Reset while the external controller is mid SPI * transaction. @@ -195,7 +204,7 @@ static void sps_configure(enum sps_mode mode, enum spi_clock_mode clk_mode, * Wait for external controller to deassert CS before * continuing. */ - while (!GREAD_FIELD(SPS, VAL, CSB)) + while (sps_cs_asserted()) ; } @@ -364,6 +373,33 @@ static void sps_rx_interrupt(uint32_t port, int cs_deasserted) static void sps_cs_deassert_interrupt(uint32_t port) { /* Make sure the receive FIFO is drained. */ + + if (sps_cs_asserted()) { + /* + * we must have been slow, this is the next CS assertion after + * the 'wake up' pulse, but we have not processed the wake up + * interrupt yet. + * + * There would be no other out of order CS assertions, as all + * the 'real' ones (as opposed to the wake up pulses) are + * confirmed by the H1 pulsing the AP interrupt line + */ + + /* + * Make sure we react to the next deassertion when it + * happens. + */ + GWRITE_FIELD(SPS, ISTATE_CLR, CS_DEASSERT, 1); + GWRITE_FIELD(SPS, FIFO_CTRL, TXFIFO_EN, 0); + if (sps_cs_asserted()) + return; + + /* + * The CS went away while we were processing this interrupt, + * this was the 'real' CS, need to process data. + */ + } + sps_rx_interrupt(port, 1); GWRITE_FIELD(SPS, ISTATE_CLR, CS_DEASSERT, 1); GWRITE_FIELD(SPS, FIFO_CTRL, TXFIFO_EN, 0); |