summaryrefslogtreecommitdiff
path: root/chip/g/sps.c
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-11-03 15:03:30 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-11-08 03:12:23 -0800
commit753247a659874a4bcbd206aa76caba23ebcf57b9 (patch)
tree146b686bcb22594522c07838cf01e976eb247492 /chip/g/sps.c
parente4579a29905dc08e4a6ed6156363b64bd03c5be3 (diff)
downloadchrome-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
Diffstat (limited to 'chip/g/sps.c')
-rw-r--r--chip/g/sps.c40
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);