summaryrefslogtreecommitdiff
path: root/board/cr50/user_pres.c
blob: 218764657f520b1fde3095afbfcc663ef896e0c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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);