diff options
Diffstat (limited to 'board/cr50/user_pres.c')
-rw-r--r-- | board/cr50/user_pres.c | 120 |
1 files changed, 120 insertions, 0 deletions
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); |