summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2018-08-29 15:45:59 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-10-30 08:42:56 -0700
commit5e6f10ed2f78b644371abb38e2e1f9a5124bc288 (patch)
treee9a9cccb4059835d181a983d62e3b778851d3c02
parentf420a49e257769b94a991416d0ebf4a30f5c9668 (diff)
downloadchrome-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>
-rw-r--r--board/kukui/emmc.c69
-rw-r--r--board/kukui/gpio.inc12
-rw-r--r--chip/stm32/gpio.c5
3 files changed, 53 insertions, 33 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;
diff --git a/board/kukui/gpio.inc b/board/kukui/gpio.inc
index 53a96f95c8..b67489fb60 100644
--- a/board/kukui/gpio.inc
+++ b/board/kukui/gpio.inc
@@ -33,21 +33,15 @@ GPIO_INT_RW(ACCEL_INT_ODL, PIN(A, 4), GPIO_INT_FALLING | GPIO_SEL_1P8V | GPIO_P
bmi160_interrupt)
GPIO_INT(CHARGER_INT_ODL, PIN(C, 13), GPIO_INT_FALLING | GPIO_PULL_UP,
rt946x_interrupt)
-#if BOARD_REV == 0
GPIO_INT_RO(EMMC_CMD, PIN(B, 15), GPIO_INT_FALLING,
emmc_cmd_interrupt)
+GPIO_INT(SPI1_NSS, PIN(A, 15), GPIO_INT_BOTH,
+ spi_event)
+#if BOARD_REV == 0
GPIO_INT_RW(SYNC_INT, PIN(A, 5), GPIO_INT_RISING | GPIO_PULL_DOWN,
sync_interrupt)
-/*
- * rev0 has an interrupt conflict between SPI1_NSS and EMMC_CMD (PIN(x, 15)),
- * let's just ignore interrupts as host command won't work anyway.
- */
GPIO(SPI1_NSS, PIN(A, 15), GPIO_INPUT)
#elif BOARD_REV >= 1
-GPIO_INT_RO(EMMC_CMD, PIN(A, 14), GPIO_INT_FALLING,
- emmc_cmd_interrupt)
-GPIO_INT(SPI1_NSS, PIN(A, 15), GPIO_INT_BOTH,
- spi_event)
GPIO_INT_RW(SYNC_INT, PIN(A, 8), GPIO_INT_RISING | GPIO_PULL_DOWN,
sync_interrupt)
GPIO_INT(HALL_INT_L, PIN(C, 5), GPIO_INT_FALLING,
diff --git a/chip/stm32/gpio.c b/chip/stm32/gpio.c
index 7108d4a10e..a8415cce1b 100644
--- a/chip/stm32/gpio.c
+++ b/chip/stm32/gpio.c
@@ -105,6 +105,7 @@ int gpio_enable_interrupt(enum gpio_signal signal)
int gpio_disable_interrupt(enum gpio_signal signal)
{
const struct gpio_info *g = gpio_list + signal;
+ uint32_t bit;
/* Fail if not implemented or no interrupt handler */
if (!g->mask || signal >= GPIO_IH_COUNT)
@@ -112,6 +113,10 @@ int gpio_disable_interrupt(enum gpio_signal signal)
STM32_EXTI_IMR &= ~g->mask;
+ bit = GPIO_MASK_TO_NUM(g->mask);
+
+ exti_events[bit] = 0;
+
return EC_SUCCESS;
}