diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2018-10-16 15:55:18 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-17 05:55:04 -0700 |
commit | 8b7f9fa4e650b7f714b05cb19088824c195742fc (patch) | |
tree | f9bfb259729e5b78fb5f449b454e58bac0ac2433 /board/kukui | |
parent | 9c84d5eb7158c91fe28c62b23e04c84355d5ada7 (diff) | |
download | chrome-ec-8b7f9fa4e650b7f714b05cb19088824c195742fc.tar.gz |
kukui/emmc: Wait for SPI FIFO to become empty (instead of 200us sleep)
It appears that the SPI FIFO takes about ~160us to become empty
(because the eMMC master stops clocking CLK), which is why adding
a delay of 200us (instead of 100us) helped get rid of the issue
described in:
c08473231923 "kukui/emmc: Wait 200us between dma_disable and flush SPI TX FIFO"
Instead of a fixed sleep time, just wait for the FIFO to become
empty, up to 1 ms (if we have to wait that long, we may hit the
bug again, but something else is probably broken).
Also, just disable TX DMA in emmc_disable_spi: we can only boot
the AP once per EC reboot anyway, so it does not matter if we
are able to feed the AP another bootblock.
BRANCH=none
BUG=b:117253718
TEST=Put kukui in a reboot loop, ~1000 sucessful boots without
ever requiring a 4th transfer.
Change-Id: I94a4b367264704d141321a54b2f2ec9616429bd9
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1282525
Reviewed-by: Yilun Lin <yllin@chromium.org>
Diffstat (limited to 'board/kukui')
-rw-r--r-- | board/kukui/emmc.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/board/kukui/emmc.c b/board/kukui/emmc.c index af2d4b1701..72b620ee06 100644 --- a/board/kukui/emmc.c +++ b/board/kukui/emmc.c @@ -35,6 +35,7 @@ #include "endian.h" #include "gpio.h" #include "hooks.h" +#include "hwtimer.h" #include "system.h" #include "task.h" #include "timer.h" @@ -103,16 +104,19 @@ static void bootblock_transfer(void) /* Abort an ongoing transfer. */ static void bootblock_stop(void) { + const uint32_t timeout = 1 * MSEC; + uint32_t start; + dma_disable(STM32_DMAC_SPI_EMMC_TX); /* - * Wait a bit to for DMA to stop writing (we can't really wait for the - * buffer to get empty, as the bus may not be clocked anymore). - * - * TODO(b:117253718): For some reason, a delay >=200us is necessary, - * else the SPI/DMA skips bytes when the transfer is resumed. + * Wait for SPI FIFO to become empty. + * We timeout after 1 ms in case the bus is not clocked anymore. */ - udelay(200); + start = __hw_clock_source_read(); + while (STM32_SPI_EMMC_REGS->sr & STM32_SPI_SR_FTLVL && + __hw_clock_source_read() - start < timeout) + ; /* Then flush SPI FIFO, and make sure DAT line stays idle (high). */ STM32_SPI_EMMC_REGS->dr = 0xff; @@ -266,8 +270,8 @@ static void emmc_disable_spi(void) hook_call_deferred(&emmc_check_status_data, -1); gpio_disable_interrupt(GPIO_EMMC_CMD); - /* Disable any pending transfer. */ - bootblock_stop(); + /* Disable TX DMA. */ + dma_disable(STM32_DMAC_SPI_EMMC_TX); /* Disable internal chip select. */ STM32_SPI_EMMC_REGS->cr1 |= STM32_SPI_CR1_SSI; /* Disable RX DMA. */ |