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)