summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c53
-rw-r--r--board/cr50/recovery_button.c45
-rw-r--r--board/cr50/recovery_button.h17
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 */