summaryrefslogtreecommitdiff
path: root/board/kukui/emmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/kukui/emmc.c')
-rw-r--r--board/kukui/emmc.c69
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;