1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <boardid.h>
4 #include <bootmode.h>
5 #include <boot/coreboot_tables.h>
6 #include <console/console.h>
7 #include <delay.h>
8 #include <drivers/i2c/ww_ring/ww_ring.h>
9 #include <gpio.h>
10 #include <soc/cdp.h>
11 #include <soc/gsbi.h>
12 #include <timer.h>
13
14 #define DEV_SW 15
15 #define REC_SW 16
16 #define WP_SW 17
17
read_gpio(gpio_t gpio_num)18 static int read_gpio(gpio_t gpio_num)
19 {
20 gpio_tlmm_config_set(gpio_num, GPIO_FUNC_DISABLE,
21 GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE);
22 udelay(10); /* Should be enough to settle. */
23 return gpio_get(gpio_num);
24 }
25
fill_lb_gpios(struct lb_gpios * gpios)26 void fill_lb_gpios(struct lb_gpios *gpios)
27 {
28 struct lb_gpio chromeos_gpios[] = {
29 {DEV_SW, ACTIVE_LOW, read_gpio(REC_SW), "presence"},
30 {-1, ACTIVE_LOW, 1, "power"},
31 {-1, ACTIVE_LOW, 0, "lid"},
32 };
33 lb_add_gpios(gpios, chromeos_gpios, ARRAY_SIZE(chromeos_gpios));
34 }
35
36 /*
37 * The recovery switch on storm is overloaded: it needs to be pressed for a
38 * certain duration at startup to signal different requests:
39 *
40 * - keeping it pressed for 8 to 16 seconds after startup signals the need for
41 * factory reset (wipeout);
42 * - keeping it pressed for longer than 16 seconds signals the need for Chrome
43 * OS recovery.
44 *
45 * The state is read once and cached for following inquiries. The below enum
46 * lists possible states.
47 */
48 enum switch_state {
49 not_probed = -1,
50 no_req,
51 recovery_req,
52 wipeout_req
53 };
54
display_pattern(int pattern)55 static void display_pattern(int pattern)
56 {
57 if (board_id() == BOARD_ID_WHIRLWIND_SP5)
58 ww_ring_display_pattern(GSBI_ID_7, pattern);
59 }
60
61 #define WIPEOUT_MODE_DELAY_MS (8 * 1000)
62 #define RECOVERY_MODE_EXTRA_DELAY_MS (8 * 1000)
63
get_switch_state(void)64 static enum switch_state get_switch_state(void)
65 {
66 struct stopwatch sw;
67 int sampled_value;
68 static enum switch_state saved_state = not_probed;
69
70 if (saved_state != not_probed)
71 return saved_state;
72
73 sampled_value = !read_gpio(REC_SW);
74
75 if (!sampled_value) {
76 saved_state = no_req;
77 display_pattern(WWR_NORMAL_BOOT);
78 return saved_state;
79 }
80
81 display_pattern(WWR_RECOVERY_PUSHED);
82 printk(BIOS_INFO, "recovery button pressed\n");
83
84 stopwatch_init_msecs_expire(&sw, WIPEOUT_MODE_DELAY_MS);
85
86 do {
87 sampled_value = !read_gpio(REC_SW);
88 if (!sampled_value)
89 break;
90 } while (!stopwatch_expired(&sw));
91
92 if (sampled_value) {
93 display_pattern(WWR_WIPEOUT_REQUEST);
94 printk(BIOS_INFO, "wipeout requested, checking recovery\n");
95 stopwatch_init_msecs_expire(&sw, RECOVERY_MODE_EXTRA_DELAY_MS);
96 do {
97 sampled_value = !read_gpio(REC_SW);
98 if (!sampled_value)
99 break;
100 } while (!stopwatch_expired(&sw));
101
102 if (sampled_value) {
103 saved_state = recovery_req;
104 display_pattern(WWR_RECOVERY_REQUEST);
105 printk(BIOS_INFO, "recovery requested\n");
106 } else {
107 saved_state = wipeout_req;
108 }
109 } else {
110 saved_state = no_req;
111 display_pattern(WWR_NORMAL_BOOT);
112 }
113
114 return saved_state;
115 }
116
get_recovery_mode_switch(void)117 int get_recovery_mode_switch(void)
118 {
119 return get_switch_state() == recovery_req;
120 }
121
get_wipeout_mode_switch(void)122 int get_wipeout_mode_switch(void)
123 {
124 return get_switch_state() == wipeout_req;
125 }
126
get_write_protect_state(void)127 int get_write_protect_state(void)
128 {
129 return !read_gpio(WP_SW);
130 }
131
get_ec_is_trusted(void)132 int get_ec_is_trusted(void)
133 {
134 /* Do not have a Chrome EC involved in entering recovery mode;
135 Always return trusted. */
136 return 1;
137 }
138