From e97da2f17c8eb188c09177b821521bebf5d830ea Mon Sep 17 00:00:00 2001 From: nagendra modadugu Date: Wed, 4 Nov 2015 18:00:55 -0800 Subject: [PATCH] Fix soft reboot to handle dropped permissions. Permission registers only reset on power cycle, so a soft reboot will fail unless a minimum power cycle is performed. BRANCH=none BUG=chrome-os-partner:47289,chrome-os-partner:43025 TEST=hard / soft reboot from ec shell Signed-off-by: nagendra modadugu Change-Id: I8f0f1bc80a2748b031a9b7a3715485577f2b5b3b Reviewed-on: https://chromium-review.googlesource.com/310975 Reviewed-by: Bill Richardson Tested-by: Nagendra Modadugu Commit-Queue: Nagendra Modadugu Trybot-Ready: Nagendra Modadugu --- board/cr50/board.c | 24 ++++++++++++++++++++++-- chip/g/system.c | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/board/cr50/board.c b/board/cr50/board.c index b90234d02d..972506e383 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -65,7 +65,25 @@ void button_event(enum gpio_signal signal) gpio_set_level(signal - GPIO_SW_N + GPIO_LED_4, v); } -static void init_interrutps(void) +static void init_pmu(void) +{ + /* This boot sequence may be a result of previous soft reset, + * in which case the PMU low power sequence register needs to + * be reset. */ + GREG32(PMU, LOW_POWER_DIS) = 0; +} + +static void init_timers(void) +{ + /* Cancel low speed timers that may have + * been initialized prior to soft reset. */ + GREG32(TIMELS, TIMER0_CONTROL) = 0; + GREG32(TIMELS, TIMER0_LOAD) = 0; + GREG32(TIMELS, TIMER1_CONTROL) = 0; + GREG32(TIMELS, TIMER1_LOAD) = 0; +} + +static void init_interrupts(void) { int i; static const enum gpio_signal gpio_signals[] = { @@ -113,7 +131,9 @@ static void init_runlevel(const enum permission_level desired_level) /* Initialize board. */ static void board_init(void) { - init_interrutps(); + init_pmu(); + init_timers(); + init_interrupts(); init_trng(); init_runlevel(PERMISSION_MEDIUM); } diff --git a/chip/g/system.c b/chip/g/system.c index 761849ad1c..0fc3334a4e 100644 --- a/chip/g/system.c +++ b/chip/g/system.c @@ -48,14 +48,38 @@ void system_reset(int flags) /* Disable interrupts to avoid task swaps during reboot */ interrupt_disable(); - if (flags & SYSTEM_RESET_HARD) /* Reset the full microcontroller */ + if (flags & SYSTEM_RESET_HARD) { + /* Reset the full microcontroller */ GR_PMU_GLOBAL_RESET = GC_PMU_GLOBAL_RESET_KEY; - else /* Reset only the CPU core */ - CPU_NVIC_APINT = 0x05fa0004; + } else { + /* Soft reset is also fairly hard, and requires + * permission registers to be reset to their initial + * state. To accomplish this, first register a wakeup + * timer and then enter lower power mode. */ - /* Spin and wait for reboot; should never return */ - while (1) - ; + /* Low speed timers continue to run in low power mode. */ + GREG32(TIMELS, TIMER1_CONTROL) = 0x1; + /* Wait for this long. */ + GREG32(TIMELS, TIMER1_LOAD) = 1; + /* Setup wake-up on Timer1 firing. */ + GREG32(PMU, EXITPD_MASK) = + GC_PMU_EXITPD_MASK_TIMELS0_PD_EXIT_TIMER1_MASK; + + /* All the components to power cycle. */ + GREG32(PMU, LOW_POWER_DIS) = + GC_PMU_LOW_POWER_DIS_VDDL_MASK | + GC_PMU_LOW_POWER_DIS_VDDIOF_MASK | + GC_PMU_LOW_POWER_DIS_VDDXO_MASK | + GC_PMU_LOW_POWER_DIS_JTR_RC_MASK; + /* Start low power sequence. */ + REG_WRITE_MLV(GREG32(PMU, LOW_POWER_DIS), + GC_PMU_LOW_POWER_DIS_START_MASK, + GC_PMU_LOW_POWER_DIS_START_LSB, + 1); + } + + /* Wait for reboot; should never return */ + asm("wfi"); } const char *system_get_chip_vendor(void)