diff options
-rw-r--r-- | board/cr50/board.c | 19 | ||||
-rw-r--r-- | board/cr50/board.h | 6 | ||||
-rw-r--r-- | board/cr50/build.mk | 1 | ||||
-rw-r--r-- | board/cr50/gpio.inc | 14 | ||||
-rw-r--r-- | board/cr50/scratch_reg1.h | 6 | ||||
-rw-r--r-- | board/cr50/user_pres.c | 120 | ||||
-rw-r--r-- | common/extension.c | 1 | ||||
-rw-r--r-- | include/tpm_vendor_cmds.h | 14 |
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. |