diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2018-08-01 18:07:30 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-08-23 13:20:38 -0700 |
commit | cac3f7c60f5a62ae3c696b02581e750c7dedb2fe (patch) | |
tree | b424c5ea87a4850b7f6afd959b5bcca2dbda546b | |
parent | 6853d78b821d3e0bdfe39dcde9b031f0eab162fa (diff) | |
download | chrome-ec-cac3f7c60f5a62ae3c696b02581e750c7dedb2fe.tar.gz |
kukui/emmc: Disable eMMC emulation when not needed
When AP is off, or after it has booted, disable eMMC emulation,
to save power.
We also add a new sleepmask bit SLEEP_MASK_EMMC to make sure the
EC does not deep sleep when emulating eMMC (timing is very critical).
We only try to emulate for 5 seconds after boot, after which we
shut down the SPI controller. 5 seconds is enough for multiple boot
attempts by the AP.
BRANCH=none
BUG=b:110907438
TEST=Power up kukui, apshutdown, powerb, repeatedly, see that AP
always boots up properly.
TEST=EC power consumption in S5/G3 drops from ~6mW to 0.6mW.
Change-Id: I32cc11418faa695ccf340784acbe7fa99bf74d8c
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1181009
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Yilun Lin <yllin@chromium.org>
-rw-r--r-- | board/kukui/emmc.c | 96 | ||||
-rw-r--r-- | include/system.h | 1 |
2 files changed, 80 insertions, 17 deletions
diff --git a/board/kukui/emmc.c b/board/kukui/emmc.c index b287402a54..36a9256817 100644 --- a/board/kukui/emmc.c +++ b/board/kukui/emmc.c @@ -34,6 +34,8 @@ #include "driver/charger/rt946x.h" #include "endian.h" #include "gpio.h" +#include "hooks.h" +#include "system.h" #include "task.h" #include "timer.h" #include "util.h" @@ -198,7 +200,7 @@ static void emmc_init_spi(void) /* Manual CS, disable. */ STM32_SPI_EMMC_REGS->cr1 = STM32_SPI_CR1_SSM | STM32_SPI_CR1_SSI; - /* Flush SPI FIFO, and make sure DAT line stays idle (high). */ + /* Flush SPI TX FIFO, and make sure DAT line stays idle (high). */ STM32_SPI_EMMC_REGS->dr = 0xff; STM32_SPI_EMMC_REGS->dr = 0xff; STM32_SPI_EMMC_REGS->dr = 0xff; @@ -207,6 +209,74 @@ static void emmc_init_spi(void) /* Enable the SPI peripheral */ STM32_SPI_EMMC_REGS->cr1 |= STM32_SPI_CR1_SPE; } +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."); +} +DECLARE_DEFERRED(emmc_check_status); + +static void emmc_enable_spi(void) +{ + if (spi_enabled) + return; + + disable_sleep(SLEEP_MASK_EMMC); + + /* Start receiving in circular buffer in_msg. */ + dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); + /* Enable internal chip select. */ + STM32_SPI_EMMC_REGS->cr1 &= ~STM32_SPI_CR1_SSI; + gpio_enable_interrupt(GPIO_EMMC_CMD); + + spi_enabled = 1; + CPRINTS("emmc enabled"); + + /* Check if AP has booted 5 seconds later. */ + hook_call_deferred(&emmc_check_status_data, 5*SECOND); +} +DECLARE_HOOK(HOOK_CHIPSET_STARTUP, emmc_enable_spi, HOOK_PRIO_FIRST); + +static void emmc_disable_spi(void) +{ + if (!spi_enabled) + return; + + /* Cancel check hook. */ + hook_call_deferred(&emmc_check_status_data, -1); + + gpio_disable_interrupt(GPIO_EMMC_CMD); + /* Disable any pending transfer. */ + bootblock_stop(); + /* Disable internal chip select. */ + STM32_SPI_EMMC_REGS->cr1 |= STM32_SPI_CR1_SSI; + /* Disable RX DMA. */ + dma_disable(STM32_DMAC_SPI_EMMC_RX); + + /* Blank out buffer to make sure we do not look at old data. */ + memset(in_msg, 0xff, sizeof(in_msg)); + + enable_sleep(SLEEP_MASK_EMMC); + + spi_enabled = 0; + CPRINTS("emmc disabled"); +} +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, emmc_disable_spi, HOOK_PRIO_FIRST); void emmc_task(void *u) { @@ -216,27 +286,19 @@ void emmc_task(void *u) /* Are we currently transmitting data? */ int tx = 0; - /* TODO(b:111773571): Remove this once we fix eMMC power supply. */ +#if BOARD_REV == 0 + /* + * TODO(b:111773571): Remove this once we fix eMMC power supply. + * Note that we never enable power to the real eMMC (we could do that + * in emmc_check_status(), but it is not trivial to do it fast + * enough). + */ mt6370_set_ldo_voltage(0); +#endif - emmc_init_spi(); - - gpio_enable_interrupt(GPIO_EMMC_CMD); - - /* Start receiving in circular buffer in_msg. */ rxdma = dma_get_channel(STM32_DMAC_SPI_EMMC_RX); - dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); - - /* Enable internal chip select. */ - STM32_SPI_EMMC_REGS->cr1 &= ~STM32_SPI_CR1_SSI; while (1) { - /* - * TODO(b:110907438): After the bootblock has been transferred - * and AP has booted, disable SPI controller and interrupt. - * TODO(b:111773571): Also, enable eMMC power supply. - */ - /* Wait for a command */ task_wait_event(-1); diff --git a/include/system.h b/include/system.h index bce8689503..c040bca840 100644 --- a/include/system.h +++ b/include/system.h @@ -431,6 +431,7 @@ enum { * detection ongoing */ SLEEP_MASK_PLL = (1 << 12), /* High-speed PLL in-use */ SLEEP_MASK_ADC = (1 << 13), /* ADC conversion ongoing */ + SLEEP_MASK_EMMC = (1 << 14), /* eMMC emulation ongoing */ SLEEP_MASK_FORCE_NO_DSLEEP = (1 << 15), /* Force disable. */ |