summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2018-08-01 18:07:30 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-08-23 13:20:38 -0700
commitcac3f7c60f5a62ae3c696b02581e750c7dedb2fe (patch)
treeb424c5ea87a4850b7f6afd959b5bcca2dbda546b
parent6853d78b821d3e0bdfe39dcde9b031f0eab162fa (diff)
downloadchrome-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.c96
-rw-r--r--include/system.h1
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. */