diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2018-08-29 15:45:59 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-30 08:42:56 -0700 |
commit | 5e6f10ed2f78b644371abb38e2e1f9a5124bc288 (patch) | |
tree | e9a9cccb4059835d181a983d62e3b778851d3c02 /board/kukui/emmc.c | |
parent | f420a49e257769b94a991416d0ebf4a30f5c9668 (diff) | |
download | chrome-ec-5e6f10ed2f78b644371abb38e2e1f9a5124bc288.tar.gz |
kukui/emmc: Share EXTI15 interrupt between SPI and eMMC
We never need to have interrupts enabled on both SPI1_NSS and
EMMC_CMD, so we can actually share the interrupt selection EXTI15
between the 2 pins. This frees up PA14 (and EXTI14) for future
interrupt needs.
To make sure that we can answer host commands as soon as the AP as
booted, we quickly poll for the eMMC bootblock switch to turn away
from EC, and switch interrupt from eMMC to SPI.
Also, we clear exit_events in chip/stm32/gpio.c, so that we do not
report a override warning if we disable then re-enable another
interrupt on the same EXTI.
BRANCH=none
BUG=b:113370127
TEST=Boot kukui rev1, check that EC commands works after boot
Change-Id: Ib1f0a56a9f37e1bda01dc4e6b55734196bb3ff50
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1195345
Reviewed-by: Yilun Lin <yllin@chromium.org>
Diffstat (limited to 'board/kukui/emmc.c')
-rw-r--r-- | board/kukui/emmc.c | 69 |
1 files changed, 45 insertions, 24 deletions
diff --git a/board/kukui/emmc.c b/board/kukui/emmc.c index b0c3d1e74b..f9fd0f9a1b 100644 --- a/board/kukui/emmc.c +++ b/board/kukui/emmc.c @@ -28,6 +28,7 @@ * case we interrupt the transfer, and the BootROM will try again. */ +#include "chipset.h" #include "clock.h" #include "console.h" #include "dma.h" @@ -57,6 +58,13 @@ #error "Please define EMMC_SPI_PORT in board.h." #endif +/* Is eMMC emulation enabled? */ +static int emmc_enabled; + +/* Maximum amount of time to wait for AP to boot. */ +static timestamp_t boot_deadline; +#define BOOT_TIMEOUT (5 * SECOND) + /* 1024 bytes circular buffer is enough for ~0.6ms @ 13Mhz. */ #define SPI_RX_BUF_BYTES 1024 #define SPI_RX_BUF_WORDS (SPI_RX_BUF_BYTES/4) @@ -219,29 +227,12 @@ static void emmc_init_spi(void) } DECLARE_HOOK(HOOK_INIT, emmc_init_spi, HOOK_PRIO_INIT_SPI); -static int spi_enabled; - -static void emmc_disable_spi(void); - -static void emmc_check_status(void) -{ - /* Bootblock switch disabled, switch off emulation */ - if (gpio_get_level(GPIO_BOOTBLOCK_EN_L) == 1) { - emmc_disable_spi(); - return; - } - - /* - * TODO(b:110907438): If we reach here, it is likely that the AP failed - * to boot, and we should try to recover from that. - */ - CPRINTS("emmc: AP failed to boot."); -} +static void emmc_check_status(void); DECLARE_DEFERRED(emmc_check_status); static void emmc_enable_spi(void) { - if (spi_enabled) + if (emmc_enabled) return; disable_sleep(SLEEP_MASK_EMMC); @@ -250,25 +241,37 @@ static void emmc_enable_spi(void) dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); /* Enable internal chip select. */ STM32_SPI_EMMC_REGS->cr1 &= ~STM32_SPI_CR1_SSI; + /* + * EMMC_CMD and SPI1_NSS share EXTI15, make sure GPIO_EMMC_CMD is + * selected. + */ + gpio_disable_interrupt(GPIO_SPI1_NSS); gpio_enable_interrupt(GPIO_EMMC_CMD); - spi_enabled = 1; + emmc_enabled = 1; CPRINTS("emmc enabled"); - /* Check if AP has booted 5 seconds later. */ - hook_call_deferred(&emmc_check_status_data, 5*SECOND); + boot_deadline.val = get_time().val + BOOT_TIMEOUT; + + /* Check if AP has booted periodically. */ + hook_call_deferred(&emmc_check_status_data, 100 * MSEC); } DECLARE_HOOK(HOOK_CHIPSET_STARTUP, emmc_enable_spi, HOOK_PRIO_FIRST); static void emmc_disable_spi(void) { - if (!spi_enabled) + if (!emmc_enabled) return; /* Cancel check hook. */ hook_call_deferred(&emmc_check_status_data, -1); gpio_disable_interrupt(GPIO_EMMC_CMD); + /* + * EMMC_CMD and SPI1_NSS share EXTI15, so re-enable interrupt on + * SPI1_NSS to reconfigure the interrupt selection. + */ + gpio_enable_interrupt(GPIO_SPI1_NSS); /* Disable TX DMA. */ dma_disable(STM32_DMAC_SPI_EMMC_TX); /* Disable internal chip select. */ @@ -281,11 +284,29 @@ static void emmc_disable_spi(void) enable_sleep(SLEEP_MASK_EMMC); - spi_enabled = 0; + emmc_enabled = 0; CPRINTS("emmc disabled"); } DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, emmc_disable_spi, HOOK_PRIO_FIRST); +static void emmc_check_status(void) +{ + /* Bootblock switch disabled, switch off emulation */ + if (gpio_get_level(GPIO_BOOTBLOCK_EN_L) == 1) { + emmc_disable_spi(); + return; + } + + if (timestamp_expired(boot_deadline, NULL)) { + CPRINTS("emmc: AP failed to boot."); + chipset_force_shutdown(CHIPSET_SHUTDOWN_BOARD_CUSTOM); + return; + } + + /* Check if AP has booted again, next time. */ + hook_call_deferred(&emmc_check_status_data, 100 * MSEC); +} + void emmc_task(void *u) { int dma_pos, i; |