diff options
-rw-r--r-- | board/cr50/board.c | 53 | ||||
-rw-r--r-- | board/cr50/recovery_button.c | 45 | ||||
-rw-r--r-- | board/cr50/recovery_button.h | 17 |
3 files changed, 111 insertions, 4 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c index ef8a91ec98..e984b9be04 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -24,6 +24,7 @@ #include "nvmem_vars.h" #include "rbox.h" #include "rdd.h" +#include "recovery_button.h" #include "registers.h" #include "scratch_reg1.h" #include "signed_header.h" @@ -757,6 +758,16 @@ static void board_init(void) bitbang_config.uart_in = ec_uart.producer.queue; /* + * Enable interrupt handler for RBOX key combo so it can be used to + * store the recovery request. + */ + if (board_uses_closed_source_set1()) { + /* Enable interrupt handler for reset button combo */ + task_enable_irq(GC_IRQNUM_RBOX0_INTR_BUTTON_COMBO0_RDY_INT); + GWRITE_FIELD(RBOX, INT_ENABLE, INTR_BUTTON_COMBO0_RDY, 1); + } + + /* * Note that the AP, EC, and servo state machines do not have explicit * init_xxx_state() functions, because they don't need to configure * registers prior to starting their state machines. Their state @@ -953,6 +964,27 @@ void board_reboot_ap(void) } /** + * Reboot the EC + */ +static void board_reboot_ec(void) +{ + assert_ec_rst(); + deassert_ec_rst(); +} + +/* + * This interrupt handler will be called if the RBOX key combo is detected. + */ +static void key_combo0_irq(void) +{ + GWRITE_FIELD(RBOX, INT_STATE, INTR_BUTTON_COMBO0_RDY, 1); + recovery_button_record(); + board_reboot_ec(); + CPRINTS("Recovery Requested"); +} +DECLARE_IRQ(GC_IRQNUM_RBOX0_INTR_BUTTON_COMBO0_RDY_INT, key_combo0_irq, 0); + +/** * Console command to toggle system (AP) reset */ static int command_sys_rst(int argc, char **argv) @@ -1039,13 +1071,28 @@ void assert_ec_rst(void) wait_ec_rst(1); } -void deassert_ec_rst(void) + +static void deassert_ec_rst_now(void) { wait_ec_rst(0); if (uart_bitbang_is_enabled()) task_enable_irq(bitbang_config.rx_irq); } +DECLARE_DEFERRED(deassert_ec_rst_now); + +void deassert_ec_rst(void) +{ + /* + * On closed source set1, the EC requires a minimum 30 ms pulse to + * properly reset. Ensure EC reset is never de-asesrted for less + * than this time. + */ + if (board_uses_closed_source_set1()) + hook_call_deferred(&deassert_ec_rst_now_data, 30 * MSEC); + else + deassert_ec_rst_now(); +} int is_ec_rst_asserted(void) { @@ -1065,9 +1112,7 @@ static int command_ec_rst(int argc, char **argv) if (!strcasecmp("pulse", argv[1])) { ccprintf("Pulsing EC reset\n"); - assert_ec_rst(); - usleep(200); - deassert_ec_rst(); + board_reboot_ec(); } else if (parse_bool(argv[1], &val)) { if (val) assert_ec_rst(); diff --git a/board/cr50/recovery_button.c b/board/cr50/recovery_button.c index af4d4d7c87..0ed4b78508 100644 --- a/board/cr50/recovery_button.c +++ b/board/cr50/recovery_button.c @@ -9,6 +9,8 @@ #include "console.h" #include "extension.h" #include "registers.h" +#include "timer.h" +#include "u2f_impl.h" #include "util.h" /* @@ -20,12 +22,53 @@ */ static uint8_t rec_btn_force_pressed; +/* + * Timestamp of the most recent recovery button press + */ +static timestamp_t last_press; + +/* How long do we latch the last recovery button press */ +#define RECOVERY_BUTTON_TIMEOUT (10 * SECOND) + +void recovery_button_record(void) +{ + last_press = get_time(); +} + +/* + * Read the recovery button latched state and unconditionally clear the state. + * + * Returns 1 iff the recovery button key combination was recorded within the + * last RECOVERY_BUTTON_TIMEOUT microseconds. Note that deep sleep also + * clears the recovery button state. + */ +static int pop_recovery_button_state(void) +{ + int latched_state = 0; + + if (last_press.val && + ((get_time().val - last_press.val) < RECOVERY_BUTTON_TIMEOUT)) + latched_state = 1; + + last_press.val = 0; + + /* Latched recovery button state */ + return latched_state; +} + static uint8_t is_rec_btn_pressed(void) { if (rec_btn_force_pressed) return 1; /* + * Platform has a defined recovery button combination and it + * the combination was pressed within a timeout + */ + if (board_uses_closed_source_set1() && pop_recovery_button_state()) + return 1; + + /* * If not force pressed, check the actual state of button. Note, * the value is inverted because the button is active low. */ @@ -68,6 +111,8 @@ static enum vendor_cmd_rc vc_get_rec_btn(enum vendor_cmd_cc code, *(uint8_t *)buf = is_rec_btn_pressed(); *response_size = 1; + ccprints("%s: state=%d", __func__, *(uint8_t *)buf); + return VENDOR_RC_SUCCESS; } DECLARE_VENDOR_COMMAND(VENDOR_CC_GET_REC_BTN, vc_get_rec_btn); diff --git a/board/cr50/recovery_button.h b/board/cr50/recovery_button.h new file mode 100644 index 0000000000..4a237a776a --- /dev/null +++ b/board/cr50/recovery_button.h @@ -0,0 +1,17 @@ +/* + * Copyright 2019 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __EC_BOARD_CR50_RECOVERY_BUTTON_H +#define __EC_BOARD_CR50_RECOVERY_BUTTON_H + +/** + * Latch a recovery button sequence. This state is latched for + * RECOVERY_BUTTON_TIMEOUT or until the AP requests the recovery button + * state. + */ +void recovery_button_record(void); + +#endif /* ! __EC_BOARD_CR50_RECOVERY_BUTTON_H */ |