summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c19
-rw-r--r--board/cr50/board.h6
-rw-r--r--board/cr50/build.mk1
-rw-r--r--board/cr50/gpio.inc14
-rw-r--r--board/cr50/scratch_reg1.h6
-rw-r--r--board/cr50/user_pres.c120
-rw-r--r--common/extension.c1
-rw-r--r--include/tpm_vendor_cmds.h14
8 files changed, 174 insertions, 7 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 567ef45d27..b47bb4f611 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -189,6 +189,25 @@ int board_get_ccd_rec_lid_pin(void)
return board_properties & BOARD_CCD_REC_LID_PIN_MASK;
}
+int board_use_diom4(void)
+{
+ return !!(board_properties & BOARD_USE_DIOM4);
+}
+
+void board_write_prop(uint32_t flag, uint8_t enable)
+{
+ GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 1);
+ /* Update board_properties and long life scratch. */
+ if (enable) {
+ board_properties |= flag;
+ GREG32(PMU, LONG_LIFE_SCRATCH1) |= flag;
+ } else {
+ board_properties &= ~flag;
+ GREG32(PMU, LONG_LIFE_SCRATCH1) &= ~flag;
+ }
+ /* Disable access to LONG_LIFE_SCRATCH1 reg */
+ GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 0);
+}
/* Get header address of the backup RW copy. */
const struct SignedHeader *get_other_rw_addr(void)
diff --git a/board/cr50/board.h b/board/cr50/board.h
index a42df3038f..a0586256d8 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -294,6 +294,7 @@ void ec_detect_asserted(enum gpio_signal signal);
void servo_detect_asserted(enum gpio_signal signal);
void tpm_rst_deasserted(enum gpio_signal signal);
void tpm_rst_asserted(enum gpio_signal signal);
+void diom4_deasserted(enum gpio_signal signal);
void post_reboot_request(void);
@@ -361,6 +362,11 @@ int board_has_ec_cr50_comm_support(void);
int board_id_is_mismatched(void);
/* Allow for deep sleep to be enabled on AP shutdown */
int board_deep_sleep_allowed(void);
+/* The board uses DIOM4 for user_pres_l */
+int board_use_diom4(void);
+
+/* Set or clear a board property flag in long life scratch. */
+void board_write_prop(uint32_t flag, uint8_t enable);
void power_button_record(void);
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index f92a527ad8..d3e55093a9 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -113,6 +113,7 @@ board-${CONFIG_RDD} += rdd.o
board-${CONFIG_USB_SPI_V2} += usb_spi.o
board-${CONFIG_USB_I2C} += usb_i2c.o
board-y += recovery_button.o
+board-y += user_pres.o
fips-y=
fips-y += dcrypto/fips.o
diff --git a/board/cr50/gpio.inc b/board/cr50/gpio.inc
index 8fb67bd425..a89aae20b5 100644
--- a/board/cr50/gpio.inc
+++ b/board/cr50/gpio.inc
@@ -127,6 +127,12 @@ GPIO_INT(EC_PACKET_MODE_EN, PIN(1, 7), GPIO_INT_RISING, ec_comm_packet_mode_en)
GPIO_INT(EC_PACKET_MODE_DIS, PIN(1, 8), GPIO_INT_FALLING,
ec_comm_packet_mode_dis)
+/*
+ * Generic pulled up input used for physical presence indication on some
+ * devices.
+ */
+GPIO_INT(DIOM4, PIN(0, 3), GPIO_INT_RISING, diom4_deasserted)
+
/*****************************************************************************/
/* NON STANDARD INTERRUPT GPIOs - handlers defined and configured in board.c */
/*
@@ -172,12 +178,6 @@ GPIO(SPI_MOSI, PIN(0, 7), GPIO_INPUT | GPIO_PULL_DOWN)
GPIO(SPI_CLK, PIN(0, 8), GPIO_INPUT | GPIO_PULL_DOWN)
GPIO(SPI_CS_L, PIN(0, 9), GPIO_INPUT)
-/*
- * Generic pulled up input used for physical presence indication on some
- * devices.
- */
-GPIO(DIOM4, PIN(0, 3), GPIO_INPUT)
-
/* Used during *chip* factory process. */
GPIO(DIOB4, PIN(0, 10), GPIO_INPUT | GPIO_PULL_DOWN)
@@ -242,7 +242,7 @@ UNIMPLEMENTED(ENTERING_RW)
/* GPIOs - mark outputs as inputs too, to read back from the driven pad */
PINMUX(GPIO(INT_AP_L), A5, DIO_INPUT)
-PINMUX(GPIO(DIOM4), M4, DIO_INPUT | GPIO_PULL_UP)
+PINMUX(GPIO(DIOM4), M4, DIO_INPUT)
PINMUX(GPIO(EC_FLASH_SELECT), B2, DIO_INPUT)
PINMUX(GPIO(MONITOR_I2CP_SDA), A1, GPIO_INPUT)
diff --git a/board/cr50/scratch_reg1.h b/board/cr50/scratch_reg1.h
index b4cdd9c6d8..a7ad0c0b14 100644
--- a/board/cr50/scratch_reg1.h
+++ b/board/cr50/scratch_reg1.h
@@ -100,6 +100,11 @@
#define BOARD_CCD_REC_LID_PIN_DIOA12 (3 << BOARD_CCD_REC_LID_PIN_SHIFT)
/*
+ * The board supports USER_PRES on DIOM4.
+ */
+#define BOARD_USE_DIOM4 BIT(24)
+
+/*
* Indicates successful completion of FIPS power up
* tests earlier. Reduces wake up time after sleep.
* Stored in PWRDN_SCRATCH22 and use multiple bits to harden against
@@ -123,6 +128,7 @@
BOARD_PERIPH_CONFIG_I2C | \
BOARD_PERIPH_CONFIG_SPI | \
BOARD_USE_PLT_RESET | \
+ BOARD_USE_DIOM4 | \
BOARD_WP_DISABLE_DELAY)
#endif /* ! __EC_BOARD_CR50_SCRATCH_REG1_H */
diff --git a/board/cr50/user_pres.c b/board/cr50/user_pres.c
new file mode 100644
index 0000000000..218764657f
--- /dev/null
+++ b/board/cr50/user_pres.c
@@ -0,0 +1,120 @@
+/* Copyright 2022 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.
+ *
+ * Track USER_PRES_L
+ */
+#include "extension.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "scratch_reg1.h"
+#include "timer.h"
+
+static uint64_t last_press;
+static uint8_t asserted;
+
+/* Save the timestamp when DIOM4 is deasserted. */
+void diom4_deasserted(enum gpio_signal unused)
+{
+ if (!board_use_diom4())
+ return;
+
+ asserted = 1;
+ last_press = get_time().val;
+}
+
+void disable_user_pres(void)
+{
+ asserted = 0;
+ gpio_set_wakepin(GPIO_DIOM4, 0);
+ /* Disable the pullup and input on DIOM4 */
+ GWRITE_FIELD(PINMUX, DIOM4_CTL, PU, 0);
+ GWRITE_FIELD(PINMUX, DIOM4_CTL, IE, 0);
+ gpio_disable_interrupt(GPIO_DIOM4);
+}
+
+void enable_user_pres(void)
+{
+ /*
+ * The interrupt happens on the rising edge. Wake on the falling edge
+ * to ensure cr50 sees the rising edge interrupt.
+ */
+ gpio_set_wakepin(GPIO_DIOM4, GPIO_HIB_WAKE_FALLING);
+ /*
+ * Some boards don't have an external pull up. Add an internal one to
+ * make sure the signal isn't floating.
+ * Enable the pullup and input on DIOM4
+ */
+ GWRITE_FIELD(PINMUX, DIOM4_CTL, PU, 1);
+ GWRITE_FIELD(PINMUX, DIOM4_CTL, IE, 1);
+ /* Enable interrupts for user_pres_l detection */
+ gpio_enable_interrupt(GPIO_DIOM4);
+}
+
+/*
+ * Vendor command to for tracking USER_PRES_L
+ *
+ * This vendor command can be used to enable tracking USER_PRES_L on DIOM4 and
+ * get the time since DIOM4 was deasserted.
+ *
+ * checks:
+ * - batt_is_present - Factory reset can only be done if HW write protect is
+ * removed.
+ * - FWMP disables ccd - If FWMP has disabled ccd, then we can't bypass it with
+ * a factory reset.
+ * - CCD password is set - If there is a password, someone will have to use that
+ * to open ccd and enable ccd manually. A factory reset cannot be
+ * used to get around the password.
+ */
+static enum vendor_cmd_rc vc_user_pres(enum vendor_cmd_cc code,
+ void *buf,
+ size_t input_size,
+ size_t *response_size)
+{
+ struct user_pres_response response;
+ uint8_t *buffer = buf;
+
+ *response_size = 0;
+
+ if (input_size == 1) {
+ uint8_t *cmd = buffer;
+
+ if (*cmd == USER_PRES_DISABLE) {
+ board_write_prop(BOARD_USE_DIOM4, 0);
+ disable_user_pres();
+ } else if (*cmd == USER_PRES_ENABLE) {
+ board_write_prop(BOARD_USE_DIOM4, 1);
+ enable_user_pres();
+ } else {
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+ return VENDOR_RC_SUCCESS;
+ } else if (input_size) {
+ return VENDOR_RC_BOGUS_ARGS;
+ }
+ *response_size = sizeof(response);
+ response.state = board_use_diom4() ? USER_PRES_ENABLE :
+ USER_PRES_DISABLE;
+ if (board_use_diom4() && asserted) {
+ response.state |= USER_PRES_PRESSED;
+ response.last_press = get_time().val - last_press;
+ }
+ memcpy(buffer, &response, sizeof(response));
+
+ return VENDOR_RC_SUCCESS;
+}
+DECLARE_VENDOR_COMMAND(VENDOR_CC_USER_PRES, vc_user_pres);
+
+/**
+ * Setup DIOM4 interrupts if the board uses them.
+ */
+static void init_user_pres(void)
+{
+ if (!board_use_diom4()) {
+ disable_user_pres();
+ return;
+ }
+ enable_user_pres();
+}
+DECLARE_HOOK(HOOK_INIT, init_user_pres, HOOK_PRIO_DEFAULT);
diff --git a/common/extension.c b/common/extension.c
index 92e4798dce..d3dcae8217 100644
--- a/common/extension.c
+++ b/common/extension.c
@@ -37,6 +37,7 @@ uint32_t extension_route_command(struct vendor_cmd_params *p)
case VENDOR_CC_RESET_EC:
case VENDOR_CC_POP_LOG_ENTRY:
case VENDOR_CC_DS_DIS_TEMP:
+ case VENDOR_CC_USER_PRES:
#endif /* defined(CR50_DEV) */
case EXTENSION_POST_RESET: /* Always need to reset. */
case VENDOR_CC_CCD:
diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h
index a59c81e10f..3ad5d79214 100644
--- a/include/tpm_vendor_cmds.h
+++ b/include/tpm_vendor_cmds.h
@@ -165,6 +165,8 @@ enum vendor_cmd_cc {
*/
VENDOR_CC_DS_DIS_TEMP = 59,
+ VENDOR_CC_USER_PRES = 60,
+
LAST_VENDOR_COMMAND = 65535,
};
@@ -224,6 +226,18 @@ enum wp_options {
WP_ENABLE
};
+/* VENDOR_CC_USER_PRES options. */
+enum user_pres_options {
+ USER_PRES_ENABLE = BIT(0),
+ USER_PRES_DISABLE = BIT(1),
+ USER_PRES_PRESSED = BIT(2)
+};
+/* Structure for VENDOR_CC_USER_PRES response */
+struct user_pres_response {
+ uint8_t state; /* The user presence state. ENABLE or DISABLE */
+ uint64_t last_press; /* Time since last press */
+} __packed;
+
/*
* The TPMv2 Spec mandates that vendor-specific command codes have bit 29 set,
* while bits 15-0 indicate the command. All other bits should be zero.