summaryrefslogtreecommitdiff
path: root/src/mainboard/google/gale/chromeos.c
blob: 2987e91d0639bdfe7eaeed77ea51b80d511286b6 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* SPDX-License-Identifier: GPL-2.0-only */

#include <boardid.h>
#include <bootmode.h>
#include <boot/coreboot_tables.h>
#include <console/console.h>
#include <delay.h>
#include <drivers/i2c/ww_ring/ww_ring.h>
#include <gpio.h>
#include <soc/cdp.h>
#include <soc/blsp.h>
#include <timer.h>

#define PP_SW   41

static int get_rec_sw_gpio_pin(void)
{
	uint8_t board_rev = board_id();

	switch (board_rev) {
	case BOARD_ID_GALE_PROTO:
	case BOARD_ID_GALE_EVT:
	case BOARD_ID_GALE_EVT2_0:
	case BOARD_ID_GALE_EVT2_1:
		return 7;
	case BOARD_ID_GALE_EVT3:
	default:
		return 57;
	}
}

static int get_wp_status_gpio_pin(void)
{
	uint8_t board_rev = board_id();
	switch (board_rev) {
	case BOARD_ID_GALE_PROTO:
	case BOARD_ID_GALE_EVT:
	case BOARD_ID_GALE_EVT2_0:
	case BOARD_ID_GALE_EVT2_1:
		return 6;
	case BOARD_ID_GALE_EVT3:
	default:
		return 53;
	}
}
static int read_gpio(gpio_t gpio_num)
{
	gpio_tlmm_config_set(gpio_num, GPIO_FUNC_DISABLE,
			     GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE);
	udelay(10); /* Should be enough to settle. */
	return gpio_get(gpio_num);
}

void fill_lb_gpios(struct lb_gpios *gpios)
{
	struct lb_gpio chromeos_gpios[] = {
		{PP_SW, ACTIVE_LOW, read_gpio(PP_SW), "presence"},
		{-1, ACTIVE_LOW, 1, "power"},
		{-1, ACTIVE_LOW, 0, "lid"},
	};
	lb_add_gpios(gpios, chromeos_gpios, ARRAY_SIZE(chromeos_gpios));
}

/*
 * The recovery switch on storm is overloaded: it needs to be pressed for a
 * certain duration at startup to signal different requests:
 *
 * - keeping it pressed for 8 to 16 seconds after startup signals the need for
 *   factory reset (wipeout);
 * - keeping it pressed for longer than 16 seconds signals the need for Chrome
 *   OS recovery.
 *
 * The state is read once and cached for following inquiries. The below enum
 * lists possible states.
 */
enum switch_state {
	not_probed = -1,
	no_req,
	recovery_req,
	wipeout_req
};

static void display_pattern(int pattern)
{
	ww_ring_display_pattern(BLSP_QUP_ID_3, pattern);
}

#define WIPEOUT_MODE_DELAY_MS (8 * 1000)
#define RECOVERY_MODE_EXTRA_DELAY_MS (8 * 1000)

static enum switch_state get_switch_state(void)
{
	struct stopwatch sw;
	int sampled_value;
	uint8_t rec_sw;
	static enum switch_state saved_state = not_probed;

	if (saved_state != not_probed)
		return saved_state;

	rec_sw = get_rec_sw_gpio_pin();
	sampled_value = !read_gpio(rec_sw);

	if (!sampled_value) {
		saved_state = no_req;
		display_pattern(WWR_NORMAL_BOOT);
		return saved_state;
	}

	display_pattern(WWR_RECOVERY_PUSHED);
	printk(BIOS_INFO, "recovery button pressed\n");

	stopwatch_init_msecs_expire(&sw, WIPEOUT_MODE_DELAY_MS);

	do {
		sampled_value = !read_gpio(rec_sw);
		if (!sampled_value)
			break;
	} while (!stopwatch_expired(&sw));

	if (sampled_value) {
		display_pattern(WWR_WIPEOUT_REQUEST);
		printk(BIOS_INFO, "wipeout requested, checking recovery\n");
		stopwatch_init_msecs_expire(&sw, RECOVERY_MODE_EXTRA_DELAY_MS);
		do {
			sampled_value = !read_gpio(rec_sw);
			if (!sampled_value)
				break;
		} while (!stopwatch_expired(&sw));

		if (sampled_value) {
			saved_state = recovery_req;
			display_pattern(WWR_RECOVERY_REQUEST);
			printk(BIOS_INFO, "recovery requested\n");
		} else {
			saved_state = wipeout_req;
		}
	} else {
		saved_state = no_req;
		display_pattern(WWR_NORMAL_BOOT);
	}

	return saved_state;
}

int get_recovery_mode_switch(void)
{
	return get_switch_state() == recovery_req;
}

int get_wipeout_mode_switch(void)
{
	return get_switch_state() == wipeout_req;
}

int get_write_protect_state(void)
{
	return !read_gpio(get_wp_status_gpio_pin());
}