static void board_handle_reboot(void) { int flags; if (system_jumped_to_this_image()) return; if (system_get_board_version() < BOARD_MIN_ID_LOD_EN) return; /* Interrogate current reset flags from previous reboot. */ flags = system_get_reset_flags(); if (!(flags & PMIC_RESET_FLAGS)) return; /* Preserve AP off request. */ if (flags & RESET_FLAG_AP_OFF) chip_save_reset_flags(RESET_FLAG_AP_OFF); ccprintf("Restarting system with PMIC.\n"); /* Flush console */ cflush(); /* Bring down all rails but RTC rail (including EC power). */ gpio_set_flags(GPIO_BATLOW_L_PMIC_LDO_EN, GPIO_OUT_HIGH); while (1) ; /* wait here */ }
void _system_reset(int flags, int wake_from_hibernate) { uint32_t save_flags = 0; /* Disable interrupts to avoid task swaps during reboot */ interrupt_disable(); /* Save current reset reasons if necessary */ if (flags & SYSTEM_RESET_PRESERVE_FLAGS) save_flags = system_get_reset_flags() | RESET_FLAG_PRESERVED; if (flags & SYSTEM_RESET_LEAVE_AP_OFF) save_flags |= RESET_FLAG_AP_OFF; if (wake_from_hibernate) save_flags |= RESET_FLAG_HIBERNATE; else if (flags & SYSTEM_RESET_HARD) save_flags |= RESET_FLAG_HARD; else save_flags |= RESET_FLAG_SOFT; chip_save_reset_flags(save_flags); /* Trigger watchdog in 1ms */ MEC1322_WDG_LOAD = 1; MEC1322_WDG_CTL |= 1; /* Spin and wait for reboot; should never return */ while (1) ; }
void test_init(void) { uint32_t state = system_get_scratchpad(); if (state & TEST_STATE_MASK(TEST_STATE_STEP_2)) { /* Power-F3-ESC */ system_set_reset_flags(system_get_reset_flags() | RESET_FLAG_RESET_PIN); mock_key(1, 1, 1); } else if (state & TEST_STATE_MASK(TEST_STATE_STEP_3)) { /* Power-F3-Down */ system_set_reset_flags(system_get_reset_flags() | RESET_FLAG_RESET_PIN); mock_key(6, 11, 1); } }
enum power_state power_chipset_init(void) { int init_power_state; uint32_t reset_flags = system_get_reset_flags(); /* * Force the AP shutdown unless we are doing SYSJUMP. Otherwise, * the AP could stay in strange state. */ if (!(reset_flags & RESET_FLAG_SYSJUMP)) { CPRINTS("not sysjump; forcing AP shutdown"); chipset_turn_off_power_rails(); /* * The warm reset triggers AP into the RK recovery mode ( * flash SPI from USB). */ chipset_reset(0); init_power_state = POWER_G3; } else { /* In the SYSJUMP case, we check if the AP is on */ if (power_get_signals() & IN_POWER_GOOD) init_power_state = POWER_S0; else init_power_state = POWER_G3; } /* Leave power off only if requested by reset flags */ if (!(reset_flags & RESET_FLAG_AP_OFF) && !(reset_flags & RESET_FLAG_SYSJUMP)) { CPRINTS("auto_power_on set due to reset_flag 0x%x", system_get_reset_flags()); auto_power_on = 1; } /* * Some batteries use clock stretching feature, which requires * more time to be stable. See http://crosbug.com/p/28289 */ battery_wait_for_stable(); return init_power_state; }
int flash_pre_init(void) { uint32_t reset_flags = system_get_reset_flags(); uint32_t prot_flags = flash_get_protect(); int need_reset = 0; /* * If we have already jumped between images, an earlier image could * have applied write protection. Nothing additional needs to be done. */ if (reset_flags & RESET_FLAG_SYSJUMP) return EC_SUCCESS; if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { /* * Pstate wants RO protected at boot, but the write * protect register wasn't set to protect it. Force an * update to the write protect register and reboot so * it takes effect. */ flash_protect_at_boot(FLASH_WP_RO); need_reset = 1; } if (prot_flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT) { /* * Write protect register was in an inconsistent state. * Set it back to a good state and reboot. */ flash_protect_at_boot( (prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? FLASH_WP_RO : FLASH_WP_NONE); need_reset = 1; } } else if (prot_flags & (EC_FLASH_PROTECT_RO_NOW | EC_FLASH_PROTECT_ERROR_INCONSISTENT)) { /* * Write protect pin unasserted but some section is * protected. Drop it and reboot. */ unlock(STM32_FLASH_PECR_OPT_LOCK); write_optb_wrp(0); lock(); need_reset = 1; } if (need_reset) system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); return EC_SUCCESS; }
test_mockable void system_reset(int flags) { uint32_t save_flags = 0; if (flags & SYSTEM_RESET_PRESERVE_FLAGS) save_flags = system_get_reset_flags() | RESET_FLAG_PRESERVED; if (flags & SYSTEM_RESET_LEAVE_AP_OFF) save_flags |= RESET_FLAG_AP_OFF; if (flags & SYSTEM_RESET_HARD) save_flags |= RESET_FLAG_HARD; if (save_flags) save_reset_flags(save_flags); emulator_reboot(); }
/** * Check if there has been a power-on event * * This checks all power-on event signals and returns non-zero if any have been * triggered (with debounce taken into account). * * @return non-zero if there has been a power-on event, 0 if not. */ static int check_for_power_on_event(void) { int ap_off_flag; ap_off_flag = system_get_reset_flags() & RESET_FLAG_AP_OFF; system_clear_reset_flags(RESET_FLAG_AP_OFF); /* check if system is already ON */ if (power_get_signals() & IN_POWER_GOOD) { if (ap_off_flag) { CPRINTS( "system is on, but " "RESET_FLAG_AP_OFF is on"); return 0; } else { CPRINTS( "system is on, thus clear " "auto_power_on"); /* no need to arrange another power on */ auto_power_on = 0; return 1; } } /* power on requested at EC startup for recovery */ if (auto_power_on) { auto_power_on = 0; return 2; } /* Check lid open */ if (lid_opened) { lid_opened = 0; return 3; } /* check for power button press */ if (power_button_is_pressed()) return 4; if (power_request == POWER_REQ_ON) { power_request = POWER_REQ_NONE; return 5; } return 0; }
/** * Set initial power button state. */ static void set_initial_pwrbtn_state(void) { uint32_t reset_flags = system_get_reset_flags(); if (system_jumped_to_this_image() && chipset_in_state(CHIPSET_STATE_ON)) { /* * Jumped to this image while the chipset was already on, so * simply reflect the actual power button state. */ if (power_button_is_pressed()) { CPRINTS("PB init-jumped-held"); set_pwrbtn_to_pch(0); } else { CPRINTS("PB init-jumped"); } } else if ((reset_flags & RESET_FLAG_AP_OFF) || (keyboard_scan_get_boot_key() == BOOT_KEY_DOWN_ARROW)) { /* * Reset triggered by keyboard-controlled reset, and down-arrow * was held down. Or reset flags request AP off. * * Leave the main processor off. This is a fail-safe * combination for debugging failures booting the main * processor. * * Don't let the PCH see that the power button was pressed. * Otherwise, it might power on. */ CPRINTS("PB init-off"); power_button_pch_release(); } else { /* * All other EC reset conditions power on the main processor so * it can verify the EC. */ #ifdef CONFIG_BRINGUP CPRINTS("PB idle"); pwrbtn_state = PWRBTN_STATE_IDLE; #else CPRINTS("PB init-on"); pwrbtn_state = PWRBTN_STATE_INIT_ON; #endif } }
int system_is_reboot_warm(void) { uint32_t reset_flags; /* * Check reset cause here, * gpio_pre_init is executed faster than system_pre_init */ check_reset_cause(); reset_flags = system_get_reset_flags(); if ((reset_flags & RESET_FLAG_RESET_PIN) || (reset_flags & RESET_FLAG_POWER_ON) || (reset_flags & RESET_FLAG_WATCHDOG) || (reset_flags & RESET_FLAG_HARD) || (reset_flags & RESET_FLAG_SOFT) || (reset_flags & RESET_FLAG_HIBERNATE)) return 0; else return 1; }
int flash_physical_restore_state(void) { uint32_t reset_flags = system_get_reset_flags(); int version, size; const struct flash_wp_state *prev; /* * If we have already jumped between images, an earlier image could * have applied write protection. Nothing additional needs to be done. */ if (reset_flags & RESET_FLAG_SYSJUMP) { prev = (const struct flash_wp_state *)system_get_jump_tag( FLASH_SYSJUMP_TAG, &version, &size); if (prev && version == FLASH_HOOK_VERSION && size == sizeof(*prev)) entire_flash_locked = prev->entire_flash_locked; return 1; } return 0; }
static int command_sysinfo(int argc, char **argv) { ccprintf("Reset flags: 0x%08x (", system_get_reset_flags()); system_print_reset_flags(); ccprintf(")\n"); ccprintf("Copy: %s\n", system_get_image_copy_string()); ccprintf("Jumped: %s\n", system_jumped_to_this_image() ? "yes" : "no"); ccputs("Flags: "); if (system_is_locked()) { ccputs(" locked"); if (force_locked) ccputs(" (forced)"); if (disable_jump) ccputs(" jump-disabled"); } else ccputs(" unlocked"); ccputs("\n"); if (reboot_at_shutdown) ccprintf("Reboot at shutdown: %d\n", reboot_at_shutdown); return EC_SUCCESS; }
int flash_pre_init(void) { uint32_t reset_flags = system_get_reset_flags(); uint32_t prot_flags = flash_get_protect(); int need_reset = 0; if (flash_physical_restore_state()) return EC_SUCCESS; /* * If we have already jumped between images, an earlier image could * have applied write protection. Nothing additional needs to be done. */ if (reset_flags & RESET_FLAG_SYSJUMP) return EC_SUCCESS; if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { /* * Pstate wants RO protected at boot, but the write * protect register wasn't set to protect it. Force an * update to the write protect register and reboot so * it takes effect. */ flash_physical_protect_at_boot(FLASH_WP_RO); need_reset = 1; } if (registers_need_reset()) { /* * Write protect register was in an inconsistent state. * Set it back to a good state and reboot. * * TODO(crosbug.com/p/23798): this seems really similar * to the check above. One of them should be able to * go away. */ flash_protect_at_boot( (prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? FLASH_WP_RO : FLASH_WP_NONE); need_reset = 1; } } else { if (prot_flags & EC_FLASH_PROTECT_RO_NOW) { /* * Write protect pin unasserted but some section is * protected. Drop it and reboot. */ unprotect_all_blocks(); need_reset = 1; } } if ((flash_physical_get_valid_flags() & EC_FLASH_PROTECT_ALL_AT_BOOT) && (!!(prot_flags & EC_FLASH_PROTECT_ALL_AT_BOOT) != !!(prot_flags & EC_FLASH_PROTECT_ALL_NOW))) { /* * ALL_AT_BOOT and ALL_NOW should be both set or both unset * at boot. If they are not, it must be that the chip requires * OBL_LAUNCH to be set to reload option bytes. Let's reset * the system with OBL_LAUNCH set. * This assumes OBL_LAUNCH is used for hard reset in * chip/stm32/system.c. */ need_reset = 1; } if (need_reset) system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); return EC_SUCCESS; }
/** * Power button state machine. * * @param tnow Current time from usec counter */ static void state_machine(uint64_t tnow) { /* Not the time to move onto next state */ if (tnow < tnext_state) return; /* States last forever unless otherwise specified */ tnext_state = 0; switch (pwrbtn_state) { case PWRBTN_STATE_PRESSED: if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { /* * Chipset is off, so wake the chipset and send it a * long enough pulse to wake up. After that we'll * reflect the true power button state. If we don't * stretch the pulse here, the user may release the * power button before the chipset finishes waking from * hard off state. */ chipset_exit_hard_off(); tnext_state = tnow + PWRBTN_INITIAL_US; pwrbtn_state = PWRBTN_STATE_WAS_OFF; } else { /* Chipset is on, so send the chipset a pulse */ tnext_state = tnow + PWRBTN_DELAY_T0; pwrbtn_state = PWRBTN_STATE_T0; } set_pwrbtn_to_pch(0); break; case PWRBTN_STATE_T0: tnext_state = tnow + PWRBTN_DELAY_T1; pwrbtn_state = PWRBTN_STATE_T1; set_pwrbtn_to_pch(1); break; case PWRBTN_STATE_T1: /* * If the chipset is already off, don't tell it the power * button is down; it'll just cause the chipset to turn on * again. */ if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) CPRINTS("PB chipset already off"); else set_pwrbtn_to_pch(0); pwrbtn_state = PWRBTN_STATE_HELD; break; case PWRBTN_STATE_RELEASED: case PWRBTN_STATE_LID_OPEN: set_pwrbtn_to_pch(1); pwrbtn_state = PWRBTN_STATE_IDLE; break; case PWRBTN_STATE_INIT_ON: /* * Don't do anything until the charger knows the battery level. * Otherwise we could power on the AP only to shut it right * back down due to insufficient battery. */ #ifdef HAS_TASK_CHARGER if (charge_get_state() == PWR_STATE_INIT) break; #endif /* * Power the system on if possible. Gating due to insufficient * battery is handled inside set_pwrbtn_to_pch(). */ chipset_exit_hard_off(); set_pwrbtn_to_pch(0); tnext_state = get_time().val + PWRBTN_INITIAL_US; if (power_button_is_pressed()) { if (system_get_reset_flags() & RESET_FLAG_RESET_PIN) pwrbtn_state = PWRBTN_STATE_BOOT_KB_RESET; else pwrbtn_state = PWRBTN_STATE_WAS_OFF; } else { pwrbtn_state = PWRBTN_STATE_RELEASED; } break; case PWRBTN_STATE_BOOT_KB_RESET: /* Initial forced pulse is done. Ignore the actual power * button until it's released, so that holding down the * recovery combination doesn't cause the chipset to shut back * down. */ set_pwrbtn_to_pch(1); if (power_button_is_pressed()) pwrbtn_state = PWRBTN_STATE_EAT_RELEASE; else pwrbtn_state = PWRBTN_STATE_IDLE; break; case PWRBTN_STATE_WAS_OFF: /* Done stretching initial power button signal, so show the * true power button state to the PCH. */ if (power_button_is_pressed()) { /* User is still holding the power button */ pwrbtn_state = PWRBTN_STATE_HELD; } else { /* Stop stretching the power button press */ power_button_released(tnow); } break; case PWRBTN_STATE_IDLE: case PWRBTN_STATE_HELD: case PWRBTN_STATE_EAT_RELEASE: /* Do nothing */ break; } }
void usb_init(void) { int i, resume; /* USB is in use */ disable_sleep(SLEEP_MASK_USB_DEVICE); /* * Resuming from a deep sleep is a lot like a cold boot, but there are * few things that we need to do slightly differently. However, we ONLY * do them if we're really resuming due to a USB wakeup. If we're woken * for some other reason, we just do a normal USB reset. The host * doesn't mind. */ resume = ((system_get_reset_flags() & RESET_FLAG_USB_RESUME) && (GR_USB_GINTSTS & GC_USB_GINTSTS_WKUPINT_MASK)); /* TODO(crosbug.com/p/46813): Clean this up. Do only what's needed, and * use meaningful constants instead of magic numbers. */ GREG32(GLOBALSEC, DDMA0_REGION0_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DDMA0_REGION1_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DDMA0_REGION2_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DDMA0_REGION3_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION0_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION1_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION2_CTRL) = 0xffffffff; GREG32(GLOBALSEC, DUSB0_REGION3_CTRL) = 0xffffffff; /* Enable clocks */ clock_enable_module(MODULE_USB, 1); /* TODO(crbug.com/496888): set up pinmux */ gpio_config_module(MODULE_USB, 1); /* Make sure interrupts are disabled */ GR_USB_GINTMSK = 0; GR_USB_DAINTMSK = 0; GR_USB_DIEPMSK = 0; GR_USB_DOEPMSK = 0; /* Select the correct PHY */ usb_select_phy(which_phy); /* Full-Speed Serial PHY */ GR_USB_GUSBCFG = GUSBCFG_PHYSEL_FS | GUSBCFG_FSINTF_6PIN | GUSBCFG_TOUTCAL(7) /* FIXME: Magic number! 14 is for 15MHz! Use 9 for 30MHz */ | GUSBCFG_USBTRDTIM(14); if (!resume) /* Don't reset on resume, because some preserved internal state * will be lost and there's no way to restore it. */ usb_softreset(); GR_USB_GUSBCFG = GUSBCFG_PHYSEL_FS | GUSBCFG_FSINTF_6PIN | GUSBCFG_TOUTCAL(7) /* FIXME: Magic number! 14 is for 15MHz! Use 9 for 30MHz */ | GUSBCFG_USBTRDTIM(14); /* Global + DMA configuration */ /* TODO: What about the AHB Burst Length Field? It's 0 now. */ GR_USB_GAHBCFG = GAHBCFG_DMA_EN | GAHBCFG_GLB_INTR_EN | GAHBCFG_NP_TXF_EMP_LVL; /* Be in disconnected state until we are ready */ if (!resume) usb_disconnect(); if (resume) /* DEVADDR is preserved in the USB module during deep sleep, * but it doesn't show up in USB_DCFG on resume. If we don't * restore it manually too, it doesn't work. */ GR_USB_DCFG = GREG32(PMU, PWRDN_SCRATCH18); else /* Init: USB2 FS, Scatter/Gather DMA, DEVADDR = 0x00 */ GR_USB_DCFG |= DCFG_DEVSPD_FS48 | DCFG_DESCDMA; /* If we've restored a nonzero device address, update our state. */ if (GR_USB_DCFG & GC_USB_DCFG_DEVADDR_MASK) { /* Caution: We only have one config TODAY, so there's no real * difference between DS_CONFIGURED and DS_ADDRESS. */ device_state = DS_CONFIGURED; configuration_value = 1; } else { device_state = DS_DEFAULT; configuration_value = 0; } /* Now that DCFG.DesDMA is accurate, prepare the FIFOs */ setup_data_fifos(); /* If resuming, reinitialize the endpoints now. For a cold boot we'll * do this as part of handling the host-driven reset. */ if (resume) usb_init_endpoints(); /* Clear any pending interrupts */ for (i = 0; i < 16; i++) { GR_USB_DIEPINT(i) = 0xffffffff; GR_USB_DOEPINT(i) = 0xffffffff; } GR_USB_GINTSTS = 0xFFFFFFFF; /* Unmask some endpoint interrupt causes */ GR_USB_DIEPMSK = DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK; GR_USB_DOEPMSK = DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK | DOEPMSK_SETUPMSK; /* Enable interrupt handlers */ task_enable_irq(GC_IRQNUM_USB0_USBINTR); /* Allow USB interrupts to come in */ GR_USB_GINTMSK = /* NAK bits that must be cleared by the DCTL register */ GINTMSK(GOUTNAKEFF) | GINTMSK(GINNAKEFF) | /* Initialization events */ GINTMSK(USBRST) | GINTMSK(ENUMDONE) | /* Endpoint activity, cleared by the DOEPINT/DIEPINT regs */ GINTMSK(OEPINT) | GINTMSK(IEPINT) | /* Reset detected while suspended. Need to wake up. */ GINTMSK(RESETDET) | /* TODO: Do we need this? */ /* Idle, Suspend detected. Should go to sleep. */ GINTMSK(ERLYSUSP) | GINTMSK(USBSUSP) | /* Watch for first SOF */ GINTMSK(SOF); /* Device registers have been setup */ GR_USB_DCTL |= DCTL_PWRONPRGDONE; udelay(10); GR_USB_DCTL &= ~DCTL_PWRONPRGDONE; /* Clear global NAKs */ GR_USB_DCTL |= DCTL_CGOUTNAK | DCTL_CGNPINNAK; #ifndef CONFIG_USB_INHIBIT_CONNECT /* Indicate our presence to the USB host */ if (!resume) usb_connect(); #endif }
void system_common_pre_init(void) { uintptr_t addr; #ifdef CONFIG_SOFTWARE_PANIC /* * Log panic cause if watchdog caused reset. This * must happen before calculating jump_data address * because it might change panic pointer. */ if (system_get_reset_flags() & RESET_FLAG_WATCHDOG) panic_log_watchdog(); #endif /* * Put the jump data before the panic data, or at the end of RAM if * panic data is not present. */ addr = (uintptr_t)panic_get_data(); if (!addr) addr = CONFIG_RAM_BASE + CONFIG_RAM_SIZE; jdata = (struct jump_data *)(addr - sizeof(struct jump_data)); /* * Check jump data if this is a jump between images. Jumps all show up * as an unknown reset reason, because we jumped directly from one * image to another without actually triggering a chip reset. */ if (jdata->magic == JUMP_DATA_MAGIC && jdata->version >= 1 && reset_flags == 0) { /* Change in jump data struct size between the previous image * and this one. */ int delta; /* Yes, we jumped to this image */ jumped_to_image = 1; /* Restore the reset flags */ reset_flags = jdata->reset_flags | RESET_FLAG_SYSJUMP; /* * If the jump data structure isn't the same size as the * current one, shift the jump tags to immediately before the * current jump data structure, to make room for initalizing * the new fields below. */ if (jdata->version == 1) delta = 0; /* No tags in v1, so no need for move */ else if (jdata->version == 2) delta = sizeof(struct jump_data) - JUMP_DATA_SIZE_V2; else delta = sizeof(struct jump_data) - jdata->struct_size; if (delta && jdata->jump_tag_total) { uint8_t *d = (uint8_t *)system_usable_ram_end(); memmove(d, d + delta, jdata->jump_tag_total); } /* Initialize fields added after version 1 */ if (jdata->version < 2) jdata->jump_tag_total = 0; /* Initialize fields added after version 2 */ if (jdata->version < 3) jdata->reserved0 = 0; /* Struct size is now the current struct size */ jdata->struct_size = sizeof(struct jump_data); /* * Clear the jump struct's magic number. This prevents * accidentally detecting a jump when there wasn't one, and * disallows use of system_add_jump_tag(). */ jdata->magic = 0; } else { /* Clear the whole jump_data struct */ memset(jdata, 0, sizeof(struct jump_data)); } }