blob: e9a09394bf794cc0c350be3a51dfe006f997873c [file] [log] [blame]
Angel Pons210a0082020-04-02 23:48:24 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauerd6682e82013-02-21 15:39:35 -08002
3#include <stdint.h>
Stefan Reinaueraaaf6892013-08-29 15:57:11 -07004#include <string.h>
Jenny TC1dfc2c32017-12-14 14:24:39 +05305#include <assert.h>
Tim Wawrzynczake6078292020-01-22 15:22:18 -07006#include <console/console.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -08007#include <delay.h>
Tim Wawrzynczake6078292020-01-22 15:22:18 -07008#include <device/device.h>
9#include <device/path.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080010#include <elog.h>
Simon Glass78659322016-06-10 20:58:24 -060011#include <rtc.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020012#include <security/vboot/vboot_common.h>
Tim Wawrzynczake6078292020-01-22 15:22:18 -070013#include <stdlib.h>
Daisuke Nojiriebb86be2018-01-26 17:36:44 -080014#include <timer.h>
Edward O'Callaghanb57fef92014-06-17 20:13:08 +100015
Stefan Reinauerd6682e82013-02-21 15:39:35 -080016#include "ec.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080017
Jenny TC1dfc2c32017-12-14 14:24:39 +053018#define INVALID_HCMD 0xFF
19
20/*
21 * Map UHEPI masks to non UHEPI commands in order to support old EC FW
22 * which does not support UHEPI command.
23 */
24static const struct {
25 uint8_t set_cmd;
26 uint8_t clear_cmd;
27 uint8_t get_cmd;
28} event_map[] = {
29 [EC_HOST_EVENT_MAIN] = {
30 INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR,
31 INVALID_HCMD,
32 },
33 [EC_HOST_EVENT_B] = {
34 INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR_B,
35 EC_CMD_HOST_EVENT_GET_B,
36 },
37 [EC_HOST_EVENT_SCI_MASK] = {
38 EC_CMD_HOST_EVENT_SET_SCI_MASK, INVALID_HCMD,
39 EC_CMD_HOST_EVENT_GET_SCI_MASK,
40 },
41 [EC_HOST_EVENT_SMI_MASK] = {
42 EC_CMD_HOST_EVENT_SET_SMI_MASK, INVALID_HCMD,
43 EC_CMD_HOST_EVENT_GET_SMI_MASK,
44 },
45 [EC_HOST_EVENT_ALWAYS_REPORT_MASK] = {
46 INVALID_HCMD, INVALID_HCMD, INVALID_HCMD,
47 },
48 [EC_HOST_EVENT_ACTIVE_WAKE_MASK] = {
49 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
50 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
51 },
Patrick Georgia29d2342018-05-02 17:12:49 +020052 [EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX] = {
53 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
54 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
55 },
56 [EC_HOST_EVENT_LAZY_WAKE_MASK_S3] = {
57 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
58 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
59 },
60 [EC_HOST_EVENT_LAZY_WAKE_MASK_S5] = {
61 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
62 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
63 },
Jenny TC1dfc2c32017-12-14 14:24:39 +053064};
65
Hung-Te Lin6bfbb332013-04-15 18:27:24 +080066uint8_t google_chromeec_calc_checksum(const uint8_t *data, int size)
67{
68 int csum;
69
70 for (csum = 0; size > 0; data++, size--)
71 csum += *data;
72 return (uint8_t)(csum & 0xff);
73}
74
Stefan Reinauerd6682e82013-02-21 15:39:35 -080075int google_chromeec_kbbacklight(int percent)
76{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -060077 struct ec_params_pwm_set_keyboard_backlight params = {
78 .percent = percent % 101,
79 };
80 struct ec_response_pwm_get_keyboard_backlight resp = {};
81 struct chromeec_command cmd = {
82 .cmd_code = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT,
83 .cmd_version = 0,
84 .cmd_data_in = &params,
85 .cmd_data_out = &resp,
86 .cmd_size_in = sizeof(params),
87 .cmd_size_out = sizeof(resp),
88 .cmd_dev_index = 0,
89 };
Stefan Reinauerd6682e82013-02-21 15:39:35 -080090
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -060091 google_chromeec_command(&cmd);
92 printk(BIOS_DEBUG, "Google Chrome set keyboard backlight: %x status (%x)\n",
93 resp.percent, cmd.cmd_code);
94 return cmd.cmd_code;
Stefan Reinauerd6682e82013-02-21 15:39:35 -080095}
96
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -060097void google_chromeec_post(uint8_t postcode)
Stefan Reinauerd6682e82013-02-21 15:39:35 -080098{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -060099 /* backlight is a percent. postcode is a uint8_t.
100 * Convert the uint8_t to %.
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800101 */
102 postcode = (postcode/4) + (postcode/8);
103 google_chromeec_kbbacklight(postcode);
104}
105
106/*
107 * Query the EC for specified mask indicating enabled events.
108 * The EC maintains separate event masks for SMI, SCI and WAKE.
109 */
Jenny TC1dfc2c32017-12-14 14:24:39 +0530110static int google_chromeec_uhepi_cmd(uint8_t mask, uint8_t action,
111 uint64_t *value)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800112{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530113 int ret;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600114 struct ec_params_host_event params = {
115 .action = action,
116 .mask_type = mask,
117 };
118 struct ec_response_host_event resp = {};
119 struct chromeec_command cmd = {
120 .cmd_code = EC_CMD_HOST_EVENT,
121 .cmd_version = 0,
122 .cmd_data_in = &params,
123 .cmd_size_in = sizeof(params),
124 .cmd_data_out = &resp,
125 .cmd_size_out = sizeof(resp),
126 .cmd_dev_index = 0,
127 };
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800128
Jenny TC1dfc2c32017-12-14 14:24:39 +0530129 if (action != EC_HOST_EVENT_GET)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600130 params.value = *value;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530131 else
132 *value = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800133
Jenny TC1dfc2c32017-12-14 14:24:39 +0530134 ret = google_chromeec_command(&cmd);
135
136 if (action != EC_HOST_EVENT_GET)
137 return ret;
138 if (ret == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600139 *value = resp.value;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530140 return ret;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800141}
142
Jenny TC1dfc2c32017-12-14 14:24:39 +0530143static int google_chromeec_handle_non_uhepi_cmd(uint8_t hcmd, uint8_t action,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600144 uint64_t *value)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700145{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530146 int ret = -1;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600147 struct ec_params_host_event_mask params = {};
148 struct ec_response_host_event_mask resp = {};
149 struct chromeec_command cmd = {
150 .cmd_code = hcmd,
151 .cmd_version = 0,
152 .cmd_data_in = &params,
153 .cmd_size_in = sizeof(params),
154 .cmd_data_out = &resp,
155 .cmd_size_out = sizeof(resp),
156 .cmd_dev_index = 0,
157 };
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700158
Jenny TC1dfc2c32017-12-14 14:24:39 +0530159 if (hcmd == INVALID_HCMD)
160 return ret;
161
162 if (action != EC_HOST_EVENT_GET)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600163 params.mask = (uint32_t)*value;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530164 else
165 *value = 0;
166
Jenny TC1dfc2c32017-12-14 14:24:39 +0530167 ret = google_chromeec_command(&cmd);
168
169 if (action != EC_HOST_EVENT_GET)
170 return ret;
171 if (ret == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600172 *value = resp.mask;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530173
174 return ret;
175}
176
177bool google_chromeec_is_uhepi_supported(void)
178{
179#define UHEPI_SUPPORTED 1
180#define UHEPI_NOT_SUPPORTED 2
181
Arthur Heymans95b3f282019-11-20 21:23:16 +0100182 static int uhepi_support;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530183
184 if (!uhepi_support) {
185 uhepi_support = google_chromeec_check_feature
Matt DeVillier41328932018-03-04 00:05:12 -0600186 (EC_FEATURE_UNIFIED_WAKE_MASKS) > 0 ? UHEPI_SUPPORTED :
Jenny TC1dfc2c32017-12-14 14:24:39 +0530187 UHEPI_NOT_SUPPORTED;
188 printk(BIOS_DEBUG, "Chrome EC: UHEPI %s\n",
189 uhepi_support == UHEPI_SUPPORTED ?
190 "supported" : "not supported");
191 }
192 return uhepi_support == UHEPI_SUPPORTED;
193}
194
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600195static uint64_t google_chromeec_get_mask(uint8_t type)
Jenny TC1dfc2c32017-12-14 14:24:39 +0530196{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600197 uint64_t value = 0;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530198
199 if (google_chromeec_is_uhepi_supported()) {
200 google_chromeec_uhepi_cmd(type, EC_HOST_EVENT_GET, &value);
201 } else {
202 assert(type < ARRAY_SIZE(event_map));
203 google_chromeec_handle_non_uhepi_cmd(
204 event_map[type].get_cmd,
205 EC_HOST_EVENT_GET, &value);
206 }
207 return value;
208}
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600209
210static int google_chromeec_clear_mask(uint8_t type, uint64_t mask)
Jenny TC1dfc2c32017-12-14 14:24:39 +0530211{
212 if (google_chromeec_is_uhepi_supported())
213 return google_chromeec_uhepi_cmd(type,
214 EC_HOST_EVENT_CLEAR, &mask);
215
216 assert(type < ARRAY_SIZE(event_map));
217 return google_chromeec_handle_non_uhepi_cmd(
218 event_map[type].clear_cmd,
219 EC_HOST_EVENT_CLEAR, &mask);
220}
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600221
222static int __unused google_chromeec_set_mask(uint8_t type, uint64_t mask)
Jenny TC1dfc2c32017-12-14 14:24:39 +0530223{
224 if (google_chromeec_is_uhepi_supported())
225 return google_chromeec_uhepi_cmd(type,
226 EC_HOST_EVENT_SET, &mask);
227
228 assert(type < ARRAY_SIZE(event_map));
229 return google_chromeec_handle_non_uhepi_cmd(
230 event_map[type].set_cmd,
231 EC_HOST_EVENT_SET, &mask);
232}
233
234static int google_chromeec_set_s3_lazy_wake_mask(uint64_t mask)
235{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800236 printk(BIOS_DEBUG, "Chrome EC: Set S3 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530237 mask);
238 return google_chromeec_set_mask
239 (EC_HOST_EVENT_LAZY_WAKE_MASK_S3, mask);
240}
241
242static int google_chromeec_set_s5_lazy_wake_mask(uint64_t mask)
243{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800244 printk(BIOS_DEBUG, "Chrome EC: Set S5 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530245 mask);
246 return google_chromeec_set_mask
247 (EC_HOST_EVENT_LAZY_WAKE_MASK_S5, mask);
248}
249
250static int google_chromeec_set_s0ix_lazy_wake_mask(uint64_t mask)
251{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800252 printk(BIOS_DEBUG, "Chrome EC: Set S0iX LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530253 mask);
254 return google_chromeec_set_mask
255 (EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, mask);
256}
257static void google_chromeec_set_lazy_wake_masks(uint64_t s5_mask,
258 uint64_t s3_mask, uint64_t s0ix_mask)
259{
260 if (google_chromeec_set_s5_lazy_wake_mask(s5_mask))
261 printk(BIOS_DEBUG, "Error: Set S5 LAZY WAKE mask failed\n");
262 if (google_chromeec_set_s3_lazy_wake_mask(s3_mask))
263 printk(BIOS_DEBUG, "Error: Set S3 LAZY WAKE mask failed\n");
Paul Moy88900dc2018-09-14 15:24:23 -0600264 /*
265 * Make sure S0Ix is supported before trying to set up the EC's
266 * S0Ix lazy wake mask.
267 */
268 if (s0ix_mask && google_chromeec_set_s0ix_lazy_wake_mask(s0ix_mask))
Jenny TC1dfc2c32017-12-14 14:24:39 +0530269 printk(BIOS_DEBUG, "Error: Set S0iX LAZY WAKE mask failed\n");
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700270}
271
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800272uint64_t google_chromeec_get_events_b(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800273{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530274 return google_chromeec_get_mask(EC_HOST_EVENT_B);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800275}
276
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800277int google_chromeec_clear_events_b(uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700278{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530279 printk(BIOS_DEBUG,
280 "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
281 return google_chromeec_clear_mask(EC_HOST_EVENT_B, mask);
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700282}
283
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700284int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
285{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600286 struct chromeec_command cmd = {
287 .cmd_code = EC_CMD_GET_NEXT_EVENT,
288 .cmd_version = 0,
289 .cmd_data_in = NULL,
290 .cmd_size_in = 0,
291 .cmd_data_out = event,
292 .cmd_size_out = sizeof(*event),
293 .cmd_dev_index = 0,
294 };
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700295
296 return google_chromeec_command(&cmd);
297}
298
Duncan Laurie7378a172017-06-29 23:52:17 -0700299/* Get the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800300uint64_t google_chromeec_get_device_enabled_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700301{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600302 struct ec_params_device_event params = {
303 .param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS,
304 };
305 struct ec_response_device_event resp = {};
306 struct chromeec_command cmd = {
307 .cmd_code = EC_CMD_DEVICE_EVENT,
308 .cmd_version = 0,
309 .cmd_data_in = &params,
310 .cmd_size_in = sizeof(params),
311 .cmd_data_out = &resp,
312 .cmd_size_out = sizeof(resp),
313 .cmd_dev_index = 0,
314 };
Duncan Laurie7378a172017-06-29 23:52:17 -0700315
316 if (google_chromeec_command(&cmd) == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600317 return resp.event_mask;
318
Duncan Laurie7378a172017-06-29 23:52:17 -0700319 return 0;
320}
321
322/* Set the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800323int google_chromeec_set_device_enabled_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700324{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600325 struct ec_params_device_event params = {
326 .event_mask = (uint32_t)mask,
327 .param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS,
328 };
329 struct ec_response_device_event resp = {};
330 struct chromeec_command cmd = {
331 .cmd_code = EC_CMD_DEVICE_EVENT,
332 .cmd_version = 0,
333 .cmd_data_in = &params,
334 .cmd_size_in = sizeof(params),
335 .cmd_data_out = &resp,
336 .cmd_size_out = sizeof(resp),
337 .cmd_dev_index = 0,
338 };
Duncan Laurie7378a172017-06-29 23:52:17 -0700339
340 return google_chromeec_command(&cmd);
341}
342
343/* Read and clear pending device events */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800344uint64_t google_chromeec_get_device_current_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700345{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600346 struct ec_params_device_event params = {
347 .param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS,
348 };
349 struct ec_response_device_event resp = {};
350 struct chromeec_command cmd = {
351 .cmd_code = EC_CMD_DEVICE_EVENT,
352 .cmd_version = 0,
353 .cmd_data_in = &params,
354 .cmd_size_in = sizeof(params),
355 .cmd_data_out = &resp,
356 .cmd_size_out = sizeof(resp),
357 .cmd_dev_index = 0,
358 };
Duncan Laurie7378a172017-06-29 23:52:17 -0700359
360 if (google_chromeec_command(&cmd) == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600361 return resp.event_mask;
362
Duncan Laurie7378a172017-06-29 23:52:17 -0700363 return 0;
364}
365
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800366static void google_chromeec_log_device_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700367{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800368 uint64_t events;
Duncan Laurie7378a172017-06-29 23:52:17 -0700369 int i;
370
Julius Wernercd49cce2019-03-05 16:53:33 -0800371 if (!CONFIG(ELOG) || !mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700372 return;
373
374 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
375 return;
376
377 events = google_chromeec_get_device_current_events() & mask;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800378 printk(BIOS_INFO, "EC Device Events: 0x%016llx\n", events);
Duncan Laurie7378a172017-06-29 23:52:17 -0700379
380 for (i = 0; i < sizeof(events) * 8; i++) {
381 if (EC_DEVICE_EVENT_MASK(i) & events)
382 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
383 }
384}
385
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800386void google_chromeec_log_events(uint64_t mask)
Furquan Shaikh2749c522017-10-04 14:01:41 -0700387{
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700388 uint64_t events;
389 int i;
Furquan Shaikh2749c522017-10-04 14:01:41 -0700390
Julius Wernercd49cce2019-03-05 16:53:33 -0800391 if (!CONFIG(ELOG))
Furquan Shaikh2749c522017-10-04 14:01:41 -0700392 return;
393
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700394 events = google_chromeec_get_events_b() & mask;
Tim Wawrzynczak7777e1c2020-07-14 13:30:46 -0600395
396 /*
397 * This loop starts at 1 because the EC_HOST_EVENT_MASK macro subtracts
398 * 1 from its argument before applying the left-shift operator. This
399 * prevents a left-shift of -1 happening, and covers the entire 64-bit
400 * range of the event mask.
401 */
402 for (i = 1; i <= sizeof(events) * 8; i++) {
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700403 if (EC_HOST_EVENT_MASK(i) & events)
404 elog_add_event_byte(ELOG_TYPE_EC_EVENT, i);
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700405 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700406
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700407 google_chromeec_clear_events_b(events);
Furquan Shaikh2749c522017-10-04 14:01:41 -0700408}
409
410void google_chromeec_events_init(const struct google_chromeec_event_info *info,
411 bool is_s3_wakeup)
412{
413 if (is_s3_wakeup) {
414 google_chromeec_log_events(info->log_events |
415 info->s3_wake_events);
416
417 /* Log and clear device events that may wake the system. */
418 google_chromeec_log_device_events(info->s3_device_events);
419
420 /* Disable SMI and wake events. */
421 google_chromeec_set_smi_mask(0);
422
Furquan Shaikh2749c522017-10-04 14:01:41 -0700423 /* Restore SCI event mask. */
424 google_chromeec_set_sci_mask(info->sci_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530425
426 } else {
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700427 google_chromeec_set_smi_mask(info->smi_events);
428
Furquan Shaikh2749c522017-10-04 14:01:41 -0700429 google_chromeec_log_events(info->log_events |
430 info->s5_wake_events);
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700431
Jenny TC1dfc2c32017-12-14 14:24:39 +0530432 if (google_chromeec_is_uhepi_supported())
433 google_chromeec_set_lazy_wake_masks
434 (info->s5_wake_events,
435 info->s3_wake_events,
436 info->s0ix_wake_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530437 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700438
439 /* Clear wake event mask. */
440 google_chromeec_set_wake_mask(0);
441}
442
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800443int google_chromeec_check_feature(int feature)
444{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600445 struct ec_response_get_features resp = {};
446 struct chromeec_command cmd = {
447 .cmd_code = EC_CMD_GET_FEATURES,
448 .cmd_version = 0,
449 .cmd_size_in = 0,
450 .cmd_data_out = &resp,
451 .cmd_size_out = sizeof(resp),
452 .cmd_dev_index = 0,
453 };
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800454
455 if (google_chromeec_command(&cmd) != 0)
456 return -1;
457
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600458 if (feature >= 8 * sizeof(resp.flags))
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800459 return -1;
460
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600461 return resp.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800462}
463
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600464int google_chromeec_get_cmd_versions(int command, uint32_t *pmask)
465{
466 struct ec_params_get_cmd_versions_v1 params = {
467 .cmd = command,
468 };
469 struct ec_response_get_cmd_versions resp = {};
470 struct chromeec_command cmd = {
471 .cmd_code = EC_CMD_GET_CMD_VERSIONS,
472 .cmd_version = 1,
473 .cmd_size_in = sizeof(params),
474 .cmd_data_in = &params,
475 .cmd_size_out = sizeof(resp),
476 .cmd_data_out = &resp,
477 .cmd_dev_index = 0,
478 };
479
480 if (google_chromeec_command(&cmd) != 0)
481 return -1;
482
483 *pmask = resp.version_mask;
484 return 0;
485}
486
487int google_chromeec_get_vboot_hash(uint32_t offset,
488 struct ec_response_vboot_hash *resp)
489{
490 struct ec_params_vboot_hash params = {
491 .cmd = EC_VBOOT_HASH_GET,
492 .offset = offset,
493 };
494 struct chromeec_command cmd = {
495 .cmd_code = EC_CMD_VBOOT_HASH,
496 .cmd_version = 0,
497 .cmd_size_in = sizeof(params),
498 .cmd_data_in = &params,
499 .cmd_size_out = sizeof(*resp),
500 .cmd_data_out = resp,
501 .cmd_dev_index = 0,
502 };
503
504 if (google_chromeec_command(&cmd) != 0)
505 return -1;
506
507 return 0;
508}
509
510int google_chromeec_start_vboot_hash(enum ec_vboot_hash_type hash_type,
511 uint32_t hash_offset,
512 struct ec_response_vboot_hash *resp)
513{
514 struct ec_params_vboot_hash params = {
515 .cmd = EC_VBOOT_HASH_START,
516 .hash_type = hash_type,
517 .nonce_size = 0,
518 .offset = hash_offset,
519 };
520 struct chromeec_command cmd = {
521 .cmd_code = EC_CMD_VBOOT_HASH,
522 .cmd_version = 0,
523 .cmd_size_in = sizeof(params),
524 .cmd_data_in = &params,
525 .cmd_size_out = sizeof(*resp),
526 .cmd_data_out = resp,
527 .cmd_dev_index = 0,
528 };
529
530 if (google_chromeec_command(&cmd) != 0)
531 return -1;
532
533 return 0;
534}
535
536int google_chromeec_flash_protect(uint32_t mask, uint32_t flags,
537 struct ec_response_flash_protect *resp)
538{
539 struct ec_params_flash_protect params = {
540 .mask = mask,
541 .flags = flags,
542 };
543 struct chromeec_command cmd = {
544 .cmd_code = EC_CMD_FLASH_PROTECT,
545 .cmd_version = EC_VER_FLASH_PROTECT,
546 .cmd_size_in = sizeof(params),
547 .cmd_data_in = &params,
548 .cmd_size_out = sizeof(*resp),
549 .cmd_data_out = resp,
550 .cmd_dev_index = 0,
551 };
552
553 if (google_chromeec_command(&cmd) != 0)
554 return -1;
555
556 return 0;
557}
558
559int google_chromeec_flash_region_info(enum ec_flash_region region,
560 uint32_t *offset, uint32_t *size)
561{
562 struct ec_params_flash_region_info params = {
563 .region = region,
564 };
565 struct ec_response_flash_region_info resp = {};
566 struct chromeec_command cmd = {
567 .cmd_code = EC_CMD_FLASH_REGION_INFO,
568 .cmd_version = EC_VER_FLASH_REGION_INFO,
569 .cmd_size_in = sizeof(params),
570 .cmd_data_in = &params,
571 .cmd_size_out = sizeof(resp),
572 .cmd_data_out = &resp,
573 .cmd_dev_index = 0,
574 };
575
576 if (google_chromeec_command(&cmd) != 0)
577 return -1;
578
579 if (offset)
580 *offset = resp.offset;
581 if (size)
582 *size = resp.size;
583
584 return 0;
585}
586
587int google_chromeec_flash_erase(uint32_t offset, uint32_t size)
588{
589 struct ec_params_flash_erase params = {
590 .offset = offset,
591 .size = size,
592 };
593 struct chromeec_command cmd = {
594 .cmd_code = EC_CMD_FLASH_ERASE,
595 .cmd_version = 0,
596 .cmd_size_in = sizeof(params),
597 .cmd_data_in = &params,
598 .cmd_size_out = 0,
599 .cmd_data_out = NULL,
600 .cmd_dev_index = 0,
601 };
602
603 if (google_chromeec_command(&cmd) != 0)
604 return -1;
605
606 return 0;
607}
608
609int google_chromeec_flash_info(struct ec_response_flash_info *info)
610{
611 struct chromeec_command cmd;
612
613 cmd.cmd_code = EC_CMD_FLASH_INFO;
614 cmd.cmd_version = 0;
615 cmd.cmd_size_in = 0;
616 cmd.cmd_data_in = NULL;
617 cmd.cmd_size_out = sizeof(*info);
618 cmd.cmd_data_out = info;
619 cmd.cmd_dev_index = 0;
620
621 if (google_chromeec_command(&cmd) != 0)
622 return -1;
623
624 return 0;
625}
626
627/*
628 * Write a block into EC flash. Expects params_data to be a buffer where
629 * the first N bytes are a struct ec_params_flash_write, and the rest of it
630 * is the data to write to flash.
631*/
632int google_chromeec_flash_write_block(const uint8_t *params_data,
633 uint32_t bufsize)
634{
635 struct chromeec_command cmd = {
636 .cmd_code = EC_CMD_FLASH_WRITE,
637 .cmd_version = EC_VER_FLASH_WRITE,
638 .cmd_size_out = 0,
639 .cmd_data_out = NULL,
640 .cmd_size_in = bufsize,
641 .cmd_data_in = params_data,
642 .cmd_dev_index = 0,
643 };
644
645 assert(params_data);
646
647 return google_chromeec_command(&cmd);
648}
649
650/*
651 * EFS verification of flash.
652 */
653int google_chromeec_efs_verify(enum ec_flash_region region)
654{
655 struct ec_params_efs_verify params = {
656 .region = region,
657 };
658 struct chromeec_command cmd = {
659 .cmd_code = EC_CMD_EFS_VERIFY,
660 .cmd_version = 0,
661 .cmd_size_in = sizeof(params),
662 .cmd_data_in = &params,
663 .cmd_size_out = 0,
664 .cmd_data_out = NULL,
665 .cmd_dev_index = 0,
666 };
667 int rv;
668
669 /* It's okay if the EC doesn't support EFS */
670 rv = google_chromeec_command(&cmd);
671 if (rv != 0 && (cmd.cmd_code == EC_RES_INVALID_COMMAND))
672 return 0;
673 else if (rv != 0)
674 return -1;
675
676 return 0;
677}
678
679int google_chromeec_battery_cutoff(uint8_t flags)
680{
681 struct ec_params_battery_cutoff params = {
682 .flags = flags,
683 };
684 struct chromeec_command cmd = {
685 .cmd_code = EC_CMD_BATTERY_CUT_OFF,
686 .cmd_version = 1,
687 .cmd_size_in = sizeof(params),
688 .cmd_data_in = &params,
689 .cmd_data_out = NULL,
690 .cmd_size_out = 0,
691 .cmd_dev_index = 0,
692 };
693
694 if (google_chromeec_command(&cmd) != 0)
695 return -1;
696
697 return 0;
698}
699
700int google_chromeec_read_limit_power_request(int *limit_power)
701{
702 struct ec_params_charge_state params = {
703 .cmd = CHARGE_STATE_CMD_GET_PARAM,
704 .get_param.param = CS_PARAM_LIMIT_POWER,
705 };
706 struct ec_response_charge_state resp = {};
707 struct chromeec_command cmd = {
708 .cmd_code = EC_CMD_CHARGE_STATE,
709 .cmd_version = 0,
710 .cmd_size_in = sizeof(params),
711 .cmd_data_in = &params,
712 .cmd_size_out = sizeof(resp),
713 .cmd_data_out = &resp,
714 .cmd_dev_index = 0,
715 };
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100716 int rv;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600717
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100718 rv = google_chromeec_command(&cmd);
Rizwan Qureshicf425782019-12-27 21:41:07 +0530719
720 if (rv != 0 && (cmd.cmd_code == EC_RES_INVALID_COMMAND ||
721 cmd.cmd_code == EC_RES_INVALID_PARAM)) {
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100722 printk(BIOS_INFO, "PARAM_LIMIT_POWER not supported by EC.\n");
723 *limit_power = 0;
724 return 0;
Rizwan Qureshicf425782019-12-27 21:41:07 +0530725 } else if (rv != 0) {
726 return -1;
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100727 }
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600728
729 *limit_power = resp.get_param.value;
Rizwan Qureshicf425782019-12-27 21:41:07 +0530730
731 return 0;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600732}
733
734int google_chromeec_get_protocol_info(
735 struct ec_response_get_protocol_info *resp)
736{
737 struct chromeec_command cmd = {
738 .cmd_code = EC_CMD_GET_PROTOCOL_INFO,
739 .cmd_version = 0,
740 .cmd_size_in = 0,
741 .cmd_data_in = NULL,
742 .cmd_data_out = resp,
743 .cmd_size_out = sizeof(*resp),
744 .cmd_dev_index = 0,
745 };
746
747 if (google_chromeec_command(&cmd))
748 return -1;
749
750 return 0;
751}
752
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600753int google_chromeec_set_sku_id(uint32_t skuid)
Kevin Chiue2bb0592017-09-12 09:13:41 +0800754{
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600755 struct ec_sku_id_info params = {
Kevin Chiue2bb0592017-09-12 09:13:41 +0800756 .sku_id = skuid
757 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600758 struct chromeec_command cmd = {
759 .cmd_code = EC_CMD_SET_SKU_ID,
760 .cmd_version = 0,
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600761 .cmd_size_in = sizeof(params),
762 .cmd_data_in = &params,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600763 .cmd_data_out = NULL,
764 .cmd_size_out = 0,
765 .cmd_dev_index = 0,
766 };
Kevin Chiue2bb0592017-09-12 09:13:41 +0800767
768 if (google_chromeec_command(&cmd) != 0)
769 return -1;
770
771 return 0;
772}
773
Julius Wernercd49cce2019-03-05 16:53:33 -0800774#if CONFIG(EC_GOOGLE_CHROMEEC_RTC)
Simon Glass78659322016-06-10 20:58:24 -0600775int rtc_get(struct rtc_time *time)
776{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600777 struct ec_response_rtc resp = {};
778 struct chromeec_command cmd = {
779 .cmd_code = EC_CMD_RTC_GET_VALUE,
780 .cmd_version = 0,
781 .cmd_size_in = 0,
782 .cmd_data_out = &resp,
783 .cmd_size_out = sizeof(resp),
784 .cmd_dev_index = 0,
785 };
Simon Glass78659322016-06-10 20:58:24 -0600786
787 if (google_chromeec_command(&cmd) != 0)
788 return -1;
789
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600790 return rtc_to_tm(resp.time, time);
Simon Glass78659322016-06-10 20:58:24 -0600791}
792#endif
793
Aaron Durbine68d22f2017-05-04 12:32:52 -0500794int google_chromeec_reboot(int dev_idx, enum ec_reboot_cmd type, uint8_t flags)
795{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600796 struct ec_params_reboot_ec params = {
Aaron Durbine68d22f2017-05-04 12:32:52 -0500797 .cmd = type,
798 .flags = flags,
799 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600800 struct ec_response_get_version resp = {};
801 struct chromeec_command cmd = {
Aaron Durbine68d22f2017-05-04 12:32:52 -0500802 .cmd_code = EC_CMD_REBOOT_EC,
803 .cmd_version = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600804 .cmd_data_in = &params,
805 .cmd_data_out = &resp,
806 .cmd_size_in = sizeof(params),
Aaron Durbine68d22f2017-05-04 12:32:52 -0500807 .cmd_size_out = 0, /* ignore response, if any */
808 .cmd_dev_index = dev_idx,
809 };
810
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600811 return google_chromeec_command(&cmd);
Aaron Durbine68d22f2017-05-04 12:32:52 -0500812}
813
Jonathan Brandmeyer6bffc5c2018-07-23 16:30:44 -0600814static int cbi_get_uint32(uint32_t *id, uint32_t tag)
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800815{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600816 struct ec_params_get_cbi params = {
817 .tag = tag,
818 };
Zhuohao Lee7824d9b2018-03-30 10:18:04 +0800819 uint32_t r = 0;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600820 struct chromeec_command cmd = {
821 .cmd_code = EC_CMD_GET_CROS_BOARD_INFO,
822 .cmd_version = 0,
823 .cmd_data_in = &params,
824 .cmd_data_out = &r,
825 .cmd_size_in = sizeof(params),
826 .cmd_size_out = sizeof(r),
827 .cmd_dev_index = 0,
828 };
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800829 int rv;
830
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800831 rv = google_chromeec_command(&cmd);
YH Lin40f65422019-02-26 09:56:06 -0800832 if (rv != 0)
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800833 return rv;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600834
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800835 *id = r;
836 return 0;
837}
838
839int google_chromeec_cbi_get_sku_id(uint32_t *id)
840{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800841 return cbi_get_uint32(id, CBI_TAG_SKU_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800842}
843
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600844int google_chromeec_cbi_get_fw_config(uint64_t *fw_config)
Jett Rink8db8a612020-01-14 11:41:47 -0700845{
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600846 uint32_t config;
847
848 if (cbi_get_uint32(&config, CBI_TAG_FW_CONFIG))
849 return -1;
850
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600851 *fw_config = (uint64_t)config;
Karthikeyan Ramasubramanian86728842021-02-25 00:29:14 -0700852 /*
853 * If SSFC is configured to be part of FW_CONFIG, add it at the most significant
854 * 32 bits.
855 */
856 if (CONFIG(EC_GOOGLE_CHROMEEC_INCLUDE_SSFC_IN_FW_CONFIG)) {
857 uint32_t ssfc;
858
Kangheui Won082be102021-04-09 15:37:15 +1000859 if (!google_chromeec_cbi_get_ssfc(&ssfc))
860 *fw_config |= (uint64_t)ssfc << 32;
Karthikeyan Ramasubramanian86728842021-02-25 00:29:14 -0700861 }
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600862 return 0;
Jett Rink8db8a612020-01-14 11:41:47 -0700863}
864
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800865int google_chromeec_cbi_get_oem_id(uint32_t *id)
866{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800867 return cbi_get_uint32(id, CBI_TAG_OEM_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800868}
869
Aaron Durbin53525772020-04-13 22:24:09 -0600870int google_chromeec_cbi_get_board_version(uint32_t *version)
871{
872 return cbi_get_uint32(version, CBI_TAG_BOARD_VERSION);
873}
874
Marco Chen525cc462020-12-11 14:29:23 +0800875int google_chromeec_cbi_get_ssfc(uint32_t *ssfc)
876{
877 return cbi_get_uint32(ssfc, CBI_TAG_SSFC);
878}
879
Wisley Chenc1efec72018-11-06 09:28:23 +0800880static int cbi_get_string(char *buf, size_t bufsize, uint32_t tag)
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600881{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600882 struct ec_params_get_cbi params = {
Wisley Chenc1efec72018-11-06 09:28:23 +0800883 .tag = tag,
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600884 };
885 struct chromeec_command cmd = {
886 .cmd_code = EC_CMD_GET_CROS_BOARD_INFO,
887 .cmd_version = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600888 .cmd_data_in = &params,
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600889 .cmd_data_out = buf,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600890 .cmd_size_in = sizeof(params),
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600891 .cmd_size_out = bufsize,
892 };
893 int rv;
894
895 rv = google_chromeec_command(&cmd);
YH Lin40f65422019-02-26 09:56:06 -0800896 if (rv != 0)
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600897 return rv;
898
899 /* Ensure NUL termination. */
900 buf[bufsize - 1] = '\0';
901
902 return 0;
903}
904
Wisley Chenc1efec72018-11-06 09:28:23 +0800905int google_chromeec_cbi_get_dram_part_num(char *buf, size_t bufsize)
906{
907 return cbi_get_string(buf, bufsize, CBI_TAG_DRAM_PART_NUM);
908}
909
910int google_chromeec_cbi_get_oem_name(char *buf, size_t bufsize)
911{
912 return cbi_get_string(buf, bufsize, CBI_TAG_OEM_NAME);
913}
914
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600915int google_chromeec_get_board_version(uint32_t *version)
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700916{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600917 struct ec_response_board_version resp;
918 struct chromeec_command cmd = {
919 .cmd_code = EC_CMD_GET_BOARD_VERSION,
920 .cmd_version = 0,
921 .cmd_size_in = 0,
922 .cmd_size_out = sizeof(resp),
923 .cmd_data_out = &resp,
924 .cmd_dev_index = 0,
925 };
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700926
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600927 if (google_chromeec_command(&cmd))
928 return -1;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700929
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600930 *version = resp.board_version;
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600931 return 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700932}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700933
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600934uint32_t google_chromeec_get_sku_id(void)
Patrick Georgi69206d92017-07-31 14:20:07 +0200935{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600936 struct ec_sku_id_info resp;
937 struct chromeec_command cmd = {
938 .cmd_code = EC_CMD_GET_SKU_ID,
939 .cmd_version = 0,
940 .cmd_size_in = 0,
941 .cmd_size_out = sizeof(resp),
942 .cmd_data_out = &resp,
943 .cmd_dev_index = 0,
944 };
Patrick Georgi69206d92017-07-31 14:20:07 +0200945
946 if (google_chromeec_command(&cmd) != 0)
947 return 0;
948
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600949 return resp.sku_id;
Patrick Georgi69206d92017-07-31 14:20:07 +0200950}
951
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700952int google_chromeec_vbnv_context(int is_read, uint8_t *data, int len)
953{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600954 struct ec_params_vbnvcontext params = {
955 .op = is_read ? EC_VBNV_CONTEXT_OP_READ :
956 EC_VBNV_CONTEXT_OP_WRITE,
957 };
958 struct ec_response_vbnvcontext resp = {};
959 struct chromeec_command cmd = {
960 .cmd_code = EC_CMD_VBNV_CONTEXT,
961 .cmd_version = EC_VER_VBNV_CONTEXT,
962 .cmd_data_in = &params,
963 .cmd_data_out = &resp,
964 .cmd_size_in = sizeof(params),
965 .cmd_size_out = is_read ? sizeof(resp) : 0,
966 .cmd_dev_index = 0,
967 };
Julius Werner02e847b2015-02-20 13:36:11 -0800968 int retries = 3;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700969
970 if (len != EC_VBNV_BLOCK_SIZE)
971 return -1;
972
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700973 if (!is_read)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600974 memcpy(&params.block, data, EC_VBNV_BLOCK_SIZE);
975retry:
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700976
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600977 if (google_chromeec_command(&cmd)) {
Julius Werner02e847b2015-02-20 13:36:11 -0800978 printk(BIOS_ERR, "ERROR: failed to %s vbnv_ec context: %d\n",
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600979 is_read ? "read" : "write", (int)cmd.cmd_code);
Julius Werner02e847b2015-02-20 13:36:11 -0800980 mdelay(10); /* just in case */
981 if (--retries)
982 goto retry;
983 }
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700984
985 if (is_read)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600986 memcpy(data, &resp.block, EC_VBNV_BLOCK_SIZE);
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700987
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600988 return cmd.cmd_code;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700989}
990
You-Cheng Syu85bb8742019-03-12 13:02:18 +0800991static uint16_t google_chromeec_get_uptime_info(
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600992 struct ec_response_uptime_info *resp)
You-Cheng Syu85bb8742019-03-12 13:02:18 +0800993{
994 struct chromeec_command cmd = {
995 .cmd_code = EC_CMD_GET_UPTIME_INFO,
996 .cmd_version = 0,
997 .cmd_data_in = NULL,
998 .cmd_size_in = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600999 .cmd_data_out = resp,
1000 .cmd_size_out = sizeof(*resp),
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001001 .cmd_dev_index = 0,
1002 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001003
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001004 google_chromeec_command(&cmd);
1005 return cmd.cmd_code;
1006}
1007
1008bool google_chromeec_get_ap_watchdog_flag(void)
1009{
Yu-Ping Wu8a82ea92021-01-05 17:05:40 +08001010 int i;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001011 struct ec_response_uptime_info resp;
Yu-Ping Wu8a82ea92021-01-05 17:05:40 +08001012
1013 if (google_chromeec_get_uptime_info(&resp))
1014 return false;
1015
1016 if (resp.ec_reset_flags & EC_RESET_FLAG_AP_WATCHDOG)
1017 return true;
1018
1019 /* Find the last valid entry */
1020 for (i = ARRAY_SIZE(resp.recent_ap_reset) - 1; i >= 0; i--) {
1021 if (resp.recent_ap_reset[i].reset_time_ms == 0)
1022 continue;
1023 return (resp.recent_ap_reset[i].reset_cause ==
1024 CHIPSET_RESET_AP_WATCHDOG);
1025 }
1026
1027 return false;
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001028}
1029
Gabe Black9f96aa62013-06-28 14:24:33 -07001030int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
1031 uint8_t *buffer, int len, int is_read)
1032{
1033 union {
1034 struct ec_params_i2c_passthru p;
1035 uint8_t outbuf[EC_HOST_PARAM_SIZE];
1036 } params;
1037 union {
1038 struct ec_response_i2c_passthru r;
1039 uint8_t inbuf[EC_HOST_PARAM_SIZE];
1040 } response;
1041 struct ec_params_i2c_passthru *p = &params.p;
1042 struct ec_response_i2c_passthru *r = &response.r;
1043 struct ec_params_i2c_passthru_msg *msg = p->msg;
1044 struct chromeec_command cmd;
1045 uint8_t *pdata;
1046 int read_len, write_len;
1047 int size;
1048 int rv;
1049
1050 p->port = 0;
1051
1052 if (alen != 1) {
1053 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
1054 return -1;
1055 }
1056 if (is_read) {
1057 read_len = len;
1058 write_len = alen;
1059 p->num_msgs = 2;
1060 } else {
1061 read_len = 0;
1062 write_len = alen + len;
1063 p->num_msgs = 1;
1064 }
1065
1066 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
1067 if (size + write_len > sizeof(params)) {
1068 printk(BIOS_ERR, "Params too large for buffer\n");
1069 return -1;
1070 }
1071 if (sizeof(*r) + read_len > sizeof(response)) {
1072 printk(BIOS_ERR, "Read length too big for buffer\n");
1073 return -1;
1074 }
1075
1076 /* Create a message to write the register address and optional data */
1077 pdata = (uint8_t *)p + size;
1078 msg->addr_flags = chip;
1079 msg->len = write_len;
1080 pdata[0] = addr;
1081 if (!is_read)
1082 memcpy(pdata + 1, buffer, len);
1083 msg++;
1084
1085 if (read_len) {
1086 msg->addr_flags = chip | EC_I2C_FLAG_READ;
1087 msg->len = read_len;
1088 }
1089
1090 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
1091 cmd.cmd_version = 0;
1092 cmd.cmd_data_in = p;
1093 cmd.cmd_size_in = size + write_len;
1094 cmd.cmd_data_out = r;
1095 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -07001096 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -07001097 rv = google_chromeec_command(&cmd);
1098 if (rv != 0)
1099 return rv;
1100
1101 /* Parse response */
1102 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
1103 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
1104 r->i2c_status);
1105 return -1;
1106 }
1107
1108 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
1109 printk(BIOS_ERR, "Truncated read response\n");
1110 return -1;
1111 }
1112
1113 if (read_len)
1114 memcpy(buffer, r->data, read_len);
1115
1116 return 0;
1117}
1118
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001119int google_chromeec_set_sci_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001120{
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001121 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +05301122 return google_chromeec_set_mask(EC_HOST_EVENT_SCI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001123}
1124
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001125int google_chromeec_set_smi_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001126{
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001127 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +05301128 return google_chromeec_set_mask(EC_HOST_EVENT_SMI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001129}
1130
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001131int google_chromeec_set_wake_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001132{
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001133 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +05301134 return google_chromeec_set_mask
1135 (EC_HOST_EVENT_ACTIVE_WAKE_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001136}
1137
Furquan Shaikh8788fd62017-11-20 20:28:18 -08001138uint64_t google_chromeec_get_wake_mask(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001139{
Jenny TC1dfc2c32017-12-14 14:24:39 +05301140 return google_chromeec_get_mask(EC_HOST_EVENT_ACTIVE_WAKE_MASK);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001141}
1142
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001143int google_chromeec_set_usb_charge_mode(uint8_t port_id, enum usb_charge_mode mode)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001144{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001145 struct ec_params_usb_charge_set_mode params = {
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001146 .usb_port_id = port_id,
1147 .mode = mode,
1148 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001149 struct chromeec_command cmd = {
1150 .cmd_code = EC_CMD_USB_CHARGE_SET_MODE,
1151 .cmd_version = 0,
1152 .cmd_size_in = sizeof(params),
1153 .cmd_data_in = &params,
1154 .cmd_size_out = 0,
1155 .cmd_data_out = NULL,
1156 .cmd_dev_index = 0,
1157 };
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001158
1159 return google_chromeec_command(&cmd);
1160}
1161
Gaggery Tsai52f18df2020-03-25 11:34:25 -07001162/* Get charger voltage and current. Also returns type of charger */
Shelley Chenebd53302017-09-29 14:15:11 -07001163int google_chromeec_get_usb_pd_power_info(enum usb_chg_type *type,
Gaggery Tsai52f18df2020-03-25 11:34:25 -07001164 uint16_t *current_max, uint16_t *voltage_max)
Shelley Chenebd53302017-09-29 14:15:11 -07001165{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001166 struct ec_params_usb_pd_power_info params = {
Shelley Chenebd53302017-09-29 14:15:11 -07001167 .port = PD_POWER_CHARGING_PORT,
1168 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001169 struct ec_response_usb_pd_power_info resp = {};
Shelley Chenebd53302017-09-29 14:15:11 -07001170 struct chromeec_command cmd = {
1171 .cmd_code = EC_CMD_USB_PD_POWER_INFO,
1172 .cmd_version = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001173 .cmd_data_in = &params,
1174 .cmd_size_in = sizeof(params),
1175 .cmd_data_out = &resp,
1176 .cmd_size_out = sizeof(resp),
Shelley Chenebd53302017-09-29 14:15:11 -07001177 .cmd_dev_index = 0,
1178 };
1179 struct usb_chg_measures m;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001180 int rv;
1181
1182 rv = google_chromeec_command(&cmd);
Shelley Chenebd53302017-09-29 14:15:11 -07001183 if (rv != 0)
1184 return rv;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001185
Shelley Chenebd53302017-09-29 14:15:11 -07001186 /* values are given in milliAmps and milliVolts */
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001187 *type = resp.type;
1188 m = resp.meas;
Gaggery Tsai52f18df2020-03-25 11:34:25 -07001189 *voltage_max = m.voltage_max;
1190 *current_max = m.current_max;
Shelley Chenebd53302017-09-29 14:15:11 -07001191 return 0;
1192}
1193
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001194int google_chromeec_override_dedicated_charger_limit(uint16_t current_lim,
1195 uint16_t voltage_lim)
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -08001196{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001197 struct ec_params_dedicated_charger_limit params = {
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -08001198 .current_lim = current_lim,
1199 .voltage_lim = voltage_lim,
1200 };
1201 struct chromeec_command cmd = {
1202 .cmd_code = EC_CMD_OVERRIDE_DEDICATED_CHARGER_LIMIT,
1203 .cmd_version = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001204 .cmd_data_in = &params,
1205 .cmd_size_in = sizeof(params),
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -08001206 .cmd_data_out = NULL,
1207 .cmd_size_out = 0,
1208 .cmd_dev_index = 0,
1209 };
1210
1211 return google_chromeec_command(&cmd);
1212}
1213
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001214int google_chromeec_set_usb_pd_role(uint8_t port, enum usb_pd_control_role role)
Julius Wernerea79d2b2016-11-21 20:14:07 -08001215{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001216 struct ec_params_usb_pd_control params = {
Julius Wernerea79d2b2016-11-21 20:14:07 -08001217 .port = port,
1218 .role = role,
1219 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
1220 .swap = USB_PD_CTRL_SWAP_NONE,
1221 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001222 struct ec_response_usb_pd_control resp;
Julius Wernerea79d2b2016-11-21 20:14:07 -08001223 struct chromeec_command cmd = {
1224 .cmd_code = EC_CMD_USB_PD_CONTROL,
1225 .cmd_version = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001226 .cmd_data_in = &params,
1227 .cmd_size_in = sizeof(params),
1228 .cmd_data_out = &resp,
1229 .cmd_size_out = sizeof(resp),
Julius Wernerea79d2b2016-11-21 20:14:07 -08001230 .cmd_dev_index = 0,
1231 };
1232
1233 return google_chromeec_command(&cmd);
1234}
1235
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001236int google_chromeec_hello(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001237{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001238 struct ec_params_hello params = {
1239 .in_data = 0x10203040,
1240 };
1241 struct ec_response_hello resp = {};
1242 struct chromeec_command cmd = {
1243 .cmd_code = EC_CMD_HELLO,
1244 .cmd_version = 0,
1245 .cmd_data_in = &params,
1246 .cmd_data_out = &resp,
1247 .cmd_size_in = sizeof(params),
1248 .cmd_size_out = sizeof(resp),
1249 .cmd_dev_index = 0,
1250 };
1251
1252 int rv = google_chromeec_command(&cmd);
1253 if (rv)
1254 return -1;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001255
1256 if (resp.out_data != (params.in_data + 0x01020304))
1257 return -1;
1258
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001259 return 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001260}
1261
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001262/*
1263 * Convert a reset cause ID to human-readable string, providing total coverage
1264 * of the 'cause' space. The returned string points to static storage and must
1265 * not be free()ed.
1266 */
1267static const char *reset_cause_to_str(uint16_t cause)
1268{
1269 /* See also ChromiumOS EC include/chipset.h for details. */
1270 static const char * const reset_causes[] = {
1271 "(reset unknown)",
1272 "reset: board custom",
1273 "reset: ap hang detected",
1274 "reset: console command",
1275 "reset: keyboard sysreset",
1276 "reset: keyboard warm reboot",
1277 "reset: debug warm reboot",
1278 "reset: at AP's request",
1279 "reset: during EC initialization",
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001280 "reset: AP watchdog",
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001281 };
1282
1283 static const size_t shutdown_cause_begin = 1 << 15;
1284 static const char * const shutdown_causes[] = {
1285 "shutdown: power failure",
1286 "shutdown: during EC initialization",
1287 "shutdown: board custom",
1288 "shutdown: battery voltage startup inhibit",
1289 "shutdown: power wait asserted",
1290 "shutdown: critical battery",
1291 "shutdown: by console command",
1292 "shutdown: entering G3",
1293 "shutdown: thermal",
1294 "shutdown: power button",
1295 };
1296
1297 if (cause < ARRAY_SIZE(reset_causes))
1298 return reset_causes[cause];
1299
1300 if (cause < shutdown_cause_begin)
1301 return "(reset unknown)";
1302
1303 if (cause < shutdown_cause_begin + ARRAY_SIZE(shutdown_causes))
1304 return shutdown_causes[cause - shutdown_cause_begin];
1305
1306 return "(shutdown unknown)";
1307}
1308
1309/*
1310 * Copy the EC's information about resets of the AP and its own uptime for
1311 * debugging purposes.
1312 */
1313static void google_chromeec_log_uptimeinfo(void)
1314{
You-Cheng Syu8d6ea6a2019-03-13 21:37:23 +08001315 /* See also ec_commands.h EC_RESET_FLAG_* for details. */
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001316 static const char * const reset_flag_strings[] = {
1317 "other",
1318 "reset-pin",
1319 "brownout",
1320 "power-on",
1321 "watchdog",
1322 "soft",
1323 "hibernate",
1324 "rtc-alarm",
1325 "wake-pin",
1326 "low-battery",
1327 "sysjump",
1328 "hard",
1329 "ap-off",
1330 "preserved",
1331 "usb-resume",
1332 "rdd",
1333 "rbox",
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001334 "security",
1335 "ap-watchdog",
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001336 };
1337 struct ec_response_uptime_info cmd_resp;
1338 int i, flag, flag_count;
1339
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001340 if (google_chromeec_get_uptime_info(&cmd_resp)) {
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001341 /*
1342 * Deliberately say nothing for EC's that don't support this
1343 * command
1344 */
1345 return;
1346 }
1347
1348 printk(BIOS_DEBUG, "Google Chrome EC uptime: %d.%03d seconds\n",
1349 cmd_resp.time_since_ec_boot_ms / MSECS_PER_SEC,
1350 cmd_resp.time_since_ec_boot_ms % MSECS_PER_SEC);
1351
1352 printk(BIOS_DEBUG, "Google Chrome AP resets since EC boot: %d\n",
1353 cmd_resp.ap_resets_since_ec_boot);
1354
1355 printk(BIOS_DEBUG, "Google Chrome most recent AP reset causes:\n");
1356 for (i = 0; i != ARRAY_SIZE(cmd_resp.recent_ap_reset); ++i) {
1357 if (cmd_resp.recent_ap_reset[i].reset_time_ms == 0)
1358 continue;
1359
1360 printk(BIOS_DEBUG, "\t%d.%03d: %d %s\n",
1361 cmd_resp.recent_ap_reset[i].reset_time_ms /
1362 MSECS_PER_SEC,
1363 cmd_resp.recent_ap_reset[i].reset_time_ms %
1364 MSECS_PER_SEC,
1365 cmd_resp.recent_ap_reset[i].reset_cause,
1366 reset_cause_to_str(
1367 cmd_resp.recent_ap_reset[i].reset_cause));
1368 }
1369
1370 printk(BIOS_DEBUG, "Google Chrome EC reset flags at last EC boot: ");
1371 flag_count = 0;
1372 for (flag = 0; flag != ARRAY_SIZE(reset_flag_strings); ++flag) {
1373 if ((cmd_resp.ec_reset_flags & (1 << flag)) != 0) {
1374 if (flag_count)
1375 printk(BIOS_DEBUG, " | ");
Greg Vae47a6f2019-10-04 02:49:20 +03001376 printk(BIOS_DEBUG, "%s", reset_flag_strings[flag]);
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001377 flag_count++;
1378 }
1379 }
1380 printk(BIOS_DEBUG, "\n");
1381}
1382
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001383/* Cache and retrieve the EC image type (ro or rw) */
Furquan Shaikha6cf8d62020-04-07 22:22:22 -07001384enum ec_image google_chromeec_get_current_image(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001385{
Kyösti Mälkkifcbbb912020-04-20 10:21:39 +03001386 static enum ec_image ec_image_type = EC_IMAGE_UNKNOWN;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001387
1388 if (ec_image_type != EC_IMAGE_UNKNOWN)
1389 return ec_image_type;
1390
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001391 struct ec_response_get_version resp = {};
1392 struct chromeec_command cmd = {
1393 .cmd_code = EC_CMD_GET_VERSION,
1394 .cmd_version = 0,
1395 .cmd_data_out = &resp,
1396 .cmd_size_in = 0,
1397 .cmd_size_out = sizeof(resp),
1398 .cmd_dev_index = 0,
1399 };
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001400
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001401 google_chromeec_command(&cmd);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001402
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001403 if (cmd.cmd_code) {
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001404 printk(BIOS_DEBUG,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001405 "Google Chrome EC: version command failed!\n");
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001406 } else {
1407 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001408 printk(BIOS_DEBUG, " ro: %s\n", resp.version_string_ro);
1409 printk(BIOS_DEBUG, " rw: %s\n", resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001410 printk(BIOS_DEBUG, " running image: %d\n",
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001411 resp.current_image);
1412 ec_image_type = resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001413 }
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001414
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001415 /* Will still be UNKNOWN if command failed */
1416 return ec_image_type;
1417}
1418
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001419int google_chromeec_get_num_pd_ports(unsigned int *num_ports)
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001420{
1421 struct ec_response_charge_port_count resp = {};
1422 struct chromeec_command cmd = {
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001423 .cmd_code = EC_CMD_USB_PD_PORTS,
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001424 .cmd_version = 0,
1425 .cmd_data_out = &resp,
1426 .cmd_size_in = 0,
1427 .cmd_size_out = sizeof(resp),
1428 .cmd_dev_index = 0,
1429 };
1430 int rv;
1431
1432 rv = google_chromeec_command(&cmd);
1433 if (rv)
1434 return rv;
1435
1436 *num_ports = resp.port_count;
1437 return 0;
1438}
1439
1440int google_chromeec_get_pd_port_caps(int port,
1441 struct usb_pd_port_caps *port_caps)
1442{
1443 struct ec_params_get_pd_port_caps params = {
1444 .port = port,
1445 };
1446 struct ec_response_get_pd_port_caps resp = {};
1447 struct chromeec_command cmd = {
1448 .cmd_code = EC_CMD_GET_PD_PORT_CAPS,
1449 .cmd_version = 0,
1450 .cmd_data_in = &params,
1451 .cmd_size_in = sizeof(params),
1452 .cmd_data_out = &resp,
1453 .cmd_size_out = sizeof(resp),
1454 .cmd_dev_index = 0,
1455 };
1456 int rv;
1457
1458 rv = google_chromeec_command(&cmd);
1459 if (rv)
1460 return rv;
1461
1462 port_caps->power_role_cap = resp.pd_power_role_cap;
1463 port_caps->try_power_role_cap = resp.pd_try_power_role_cap;
1464 port_caps->data_role_cap = resp.pd_data_role_cap;
1465 port_caps->port_location = resp.pd_port_location;
1466
1467 return 0;
1468}
1469
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001470void google_chromeec_init(void)
1471{
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001472 google_chromeec_log_uptimeinfo();
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001473}
1474
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001475int google_ec_running_ro(void)
1476{
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001477 return (google_chromeec_get_current_image() == EC_IMAGE_RO);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001478}
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001479
Derek Huang796ea822021-09-29 22:05:04 +08001480/* Returns data role and type of device connected */
1481static int google_chromeec_usb_pd_get_info(int port, bool *ufp, bool *dbg_acc,
Derek Huangf1f9b3d2021-09-29 16:39:01 +08001482 bool *active_cable, uint8_t *dp_mode)
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001483{
1484 struct ec_params_usb_pd_control pd_control = {
1485 .port = port,
1486 .role = USB_PD_CTRL_ROLE_NO_CHANGE,
1487 .mux = USB_PD_CTRL_ROLE_NO_CHANGE,
1488 .swap = USB_PD_CTRL_SWAP_NONE,
1489 };
1490 struct ec_response_usb_pd_control_v2 resp = {};
1491 struct chromeec_command cmd = {
1492 .cmd_code = EC_CMD_USB_PD_CONTROL,
1493 .cmd_version = 2,
1494 .cmd_data_in = &pd_control,
1495 .cmd_size_in = sizeof(pd_control),
1496 .cmd_data_out = &resp,
1497 .cmd_size_out = sizeof(resp),
1498 .cmd_dev_index = 0,
1499 };
1500
1501 if (google_chromeec_command(&cmd) < 0)
1502 return -1;
1503
1504 *ufp = (resp.cc_state == PD_CC_DFP_ATTACHED);
1505 *dbg_acc = (resp.cc_state == PD_CC_DFP_DEBUG_ACC);
Derek Huangf1f9b3d2021-09-29 16:39:01 +08001506 *active_cable = !!(resp.control_flags & USB_PD_CTRL_ACTIVE_CABLE);
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001507 *dp_mode = resp.dp_mode;
1508
1509 return 0;
1510}
1511
Derek Huangc0bd1232021-08-25 17:19:39 +08001512int google_chromeec_typec_control_enter_dp_mode(int port)
1513{
1514 if (!google_chromeec_check_feature(EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY))
1515 return 0;
1516
1517 struct ec_params_typec_control typec_control = {
1518 .port = port,
1519 .command = TYPEC_CONTROL_COMMAND_ENTER_MODE,
1520 .mode_to_enter = TYPEC_MODE_DP,
1521 };
1522
1523 struct chromeec_command cmd = {
1524 .cmd_code = EC_CMD_TYPEC_CONTROL,
1525 .cmd_version = 0,
1526 .cmd_data_in = &typec_control,
1527 .cmd_size_in = sizeof(typec_control),
1528 .cmd_data_out = NULL,
1529 .cmd_size_out = 0,
1530 .cmd_dev_index = 0,
1531 };
1532
1533 if (google_chromeec_command(&cmd) < 0)
1534 return -1;
1535
1536 return 0;
1537}
1538
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001539/**
1540 * Check for the current mux state in EC. Flags representing the mux state found
1541 * in ec_commands.h
1542 */
1543int google_chromeec_usb_get_pd_mux_info(int port, uint8_t *flags)
1544{
1545 struct ec_params_usb_pd_mux_info req_mux = {
1546 .port = port,
1547 };
1548 struct ec_response_usb_pd_mux_info resp_mux = {};
1549 struct chromeec_command cmd = {
1550 .cmd_code = EC_CMD_USB_PD_MUX_INFO,
1551 .cmd_version = 0,
1552 .cmd_data_in = &req_mux,
1553 .cmd_size_in = sizeof(req_mux),
1554 .cmd_data_out = &resp_mux,
1555 .cmd_size_out = sizeof(resp_mux),
1556 .cmd_dev_index = 0,
1557 };
1558
1559 if (port < 0)
1560 return -1;
1561
1562 if (google_chromeec_command(&cmd) < 0)
1563 return -1;
1564
1565 *flags = resp_mux.flags;
1566 return 0;
1567}
1568
Derek Huang63ffc1a2021-09-29 21:59:45 +08001569/*
1570 * Obtain any USB-C mux data needed for the specified port
1571 * in: physical port number of the type-c port
1572 * out: struct usbc_mux_info mux_info stores USB-C mux data
1573 * Return: 0 on success, -1 on error
1574*/
1575int google_chromeec_get_usbc_mux_info(int port, struct usbc_mux_info *mux_info)
1576{
1577 uint8_t mux_flags;
1578 uint8_t dp_pin_mode;
1579 bool ufp, dbg_acc, active_cable;
1580
1581 if (google_chromeec_usb_get_pd_mux_info(port, &mux_flags) < 0) {
1582 printk(BIOS_ERR, "Port C%d: get_pd_mux_info failed\n", port);
1583 return -1;
1584 }
1585
1586 if (google_chromeec_usb_pd_get_info(port, &ufp, &dbg_acc,
1587 &active_cable, &dp_pin_mode) < 0) {
1588 printk(BIOS_ERR, "Port C%d: pd_control failed\n", port);
1589 return -1;
1590 }
1591
1592 mux_info->usb = !!(mux_flags & USB_PD_MUX_USB_ENABLED);
1593 mux_info->dp = !!(mux_flags & USB_PD_MUX_DP_ENABLED);
1594 mux_info->polarity = !!(mux_flags & USB_PD_MUX_POLARITY_INVERTED);
1595 mux_info->hpd_irq = !!(mux_flags & USB_PD_MUX_HPD_IRQ);
1596 mux_info->hpd_lvl = !!(mux_flags & USB_PD_MUX_HPD_LVL);
1597 mux_info->ufp = !!ufp;
1598 mux_info->dbg_acc = !!dbg_acc;
1599 mux_info->cable = !!active_cable;
1600 mux_info->dp_pin_mode = dp_pin_mode;
1601
1602 return 0;
1603}
1604
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001605/**
1606 * Check if EC/TCPM is in an alternate mode or not.
1607 *
1608 * @param svid SVID of the alternate mode to check
Derek Huangc0f005a2021-09-29 17:38:31 +08001609 * @return 0: Not in the mode. -1: Error.
1610 * >=1: bitmask of the ports that are in the mode.
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001611 */
Derek Huangc0f005a2021-09-29 17:38:31 +08001612static int google_chromeec_pd_get_amode(uint16_t svid)
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001613{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001614 struct ec_response_usb_pd_ports resp;
1615 struct chromeec_command cmd = {
1616 .cmd_code = EC_CMD_USB_PD_PORTS,
1617 .cmd_version = 0,
1618 .cmd_data_in = NULL,
1619 .cmd_size_in = 0,
1620 .cmd_data_out = &resp,
1621 .cmd_size_out = sizeof(resp),
1622 .cmd_dev_index = 0,
1623 };
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001624 int i;
Derek Huangc0f005a2021-09-29 17:38:31 +08001625 int ret = 0;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001626
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001627 if (google_chromeec_command(&cmd) < 0)
1628 return -1;
1629
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001630 for (i = 0; i < resp.num_ports; i++) {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001631 struct ec_params_usb_pd_get_mode_request params;
1632 struct ec_params_usb_pd_get_mode_response resp2;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001633 int svid_idx = 0;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001634
1635 do {
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001636 /* Reset cmd in each iteration in case
1637 google_chromeec_command changes it. */
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001638 params.port = i;
1639 params.svid_idx = svid_idx;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001640 cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE;
1641 cmd.cmd_version = 0;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001642 cmd.cmd_data_in = &params;
1643 cmd.cmd_size_in = sizeof(params);
1644 cmd.cmd_data_out = &resp2;
1645 cmd.cmd_size_out = sizeof(resp2);
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001646 cmd.cmd_dev_index = 0;
1647
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001648 if (google_chromeec_command(&cmd) < 0)
1649 return -1;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001650 if (resp2.svid == svid)
Derek Huangc0f005a2021-09-29 17:38:31 +08001651 ret |= BIT(i);
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001652 svid_idx++;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001653 } while (resp2.svid);
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001654 }
1655
Derek Huangc0f005a2021-09-29 17:38:31 +08001656 return ret;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001657}
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001658
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001659#define USB_SID_DISPLAYPORT 0xff01
1660
Daisuke Nojirid182b632018-02-16 17:50:06 -08001661/**
1662 * Wait for DisplayPort to be ready
1663 *
Derek Huangc0f005a2021-09-29 17:38:31 +08001664 * @param timeout_ms Wait aborts after <timeout_ms> ms.
1665 * @return -1: Error. 0: Timeout.
1666 * >=1: Bitmask of the ports that DP device is connected
Daisuke Nojirid182b632018-02-16 17:50:06 -08001667 */
Derek Huangc0f005a2021-09-29 17:38:31 +08001668int google_chromeec_wait_for_displayport(long timeout_ms)
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001669{
1670 struct stopwatch sw;
Derek Huangc0f005a2021-09-29 17:38:31 +08001671 int ret = 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001672
Daisuke Nojirid182b632018-02-16 17:50:06 -08001673 printk(BIOS_INFO, "Waiting for DisplayPort\n");
Derek Huangc0f005a2021-09-29 17:38:31 +08001674 stopwatch_init_msecs_expire(&sw, timeout_ms);
1675 while (1) {
1676 ret = google_chromeec_pd_get_amode(USB_SID_DISPLAYPORT);
1677 if (ret > 0)
1678 break;
1679
1680 if (ret < 0) {
1681 printk(BIOS_ERR, "Can't get alternate mode!\n");
1682 return ret;
1683 }
1684
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001685 if (stopwatch_expired(&sw)) {
1686 printk(BIOS_WARNING,
Daisuke Nojirid182b632018-02-16 17:50:06 -08001687 "DisplayPort not ready after %ldms. Abort.\n",
Derek Huangc0f005a2021-09-29 17:38:31 +08001688 timeout_ms);
Daisuke Nojirid182b632018-02-16 17:50:06 -08001689 return 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001690 }
1691 mdelay(200);
1692 }
Daisuke Nojirid182b632018-02-16 17:50:06 -08001693 printk(BIOS_INFO, "DisplayPort ready after %lu ms\n",
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001694 stopwatch_duration_msecs(&sw));
Daisuke Nojirid182b632018-02-16 17:50:06 -08001695
Derek Huangc0f005a2021-09-29 17:38:31 +08001696 return ret;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001697}
Rajat Jain89eef552020-04-10 15:48:49 -07001698
Derek Huangc0bd1232021-08-25 17:19:39 +08001699int google_chromeec_wait_for_dp_hpd(int port, long timeout_ms)
1700{
1701 uint8_t mux_flags;
1702 struct stopwatch sw;
1703
1704 stopwatch_init_msecs_expire(&sw, timeout_ms);
1705 do {
1706 google_chromeec_usb_get_pd_mux_info(port, &mux_flags);
1707 if (stopwatch_expired(&sw)) {
1708 printk(BIOS_WARNING, "HPD not ready after %ldms. Abort.\n", timeout_ms);
1709 return -1;
1710 }
1711 mdelay(100);
1712 } while (!(mux_flags & USB_PD_MUX_HPD_LVL) || !(mux_flags & USB_PD_MUX_DP_ENABLED));
1713 printk(BIOS_INFO, "HPD ready after %lu ms\n", stopwatch_duration_msecs(&sw));
1714
1715 return 0;
1716}
1717
Rajat Jain89eef552020-04-10 15:48:49 -07001718int google_chromeec_get_keybd_config(struct ec_response_keybd_config *keybd)
1719{
1720 struct chromeec_command cmd = {
1721 .cmd_code = EC_CMD_GET_KEYBD_CONFIG,
1722 .cmd_version = 0,
1723 .cmd_data_in = NULL,
1724 .cmd_size_in = 0,
1725 .cmd_data_out = keybd,
1726 .cmd_size_out = sizeof(*keybd),
1727 .cmd_dev_index = 0,
1728 };
1729
1730 if (google_chromeec_command(&cmd))
1731 return -1;
1732
1733 return 0;
1734}
Karthikeyan Ramasubramanianc96d12e2020-08-04 16:50:02 -06001735
1736int google_chromeec_ap_reset(void)
1737{
1738 struct chromeec_command cmd = {
1739 .cmd_code = EC_CMD_AP_RESET,
1740 .cmd_version = 0,
1741 .cmd_data_in = NULL,
1742 .cmd_size_in = 0,
1743 .cmd_data_out = NULL,
1744 .cmd_size_out = 0,
1745 .cmd_dev_index = 0,
1746 };
1747
1748 if (google_chromeec_command(&cmd))
1749 return -1;
1750
1751 return 0;
1752}
Yidi Lin79a812e2020-09-21 20:25:54 +08001753
Yidi Lin99e6dd92020-10-23 16:02:59 +08001754int google_chromeec_regulator_enable(uint32_t index, uint8_t enable)
1755{
1756 struct ec_params_regulator_enable params = {
1757 .index = index,
1758 .enable = enable,
1759 };
1760 struct chromeec_command cmd = {
1761 .cmd_code = EC_CMD_REGULATOR_ENABLE,
1762 .cmd_version = 0,
1763 .cmd_data_in = &params,
1764 .cmd_size_in = sizeof(params),
1765 .cmd_data_out = NULL,
1766 .cmd_size_out = 0,
1767 .cmd_dev_index = 0,
1768 };
1769
1770 if (google_chromeec_command(&cmd))
1771 return -1;
1772
1773 return 0;
1774}
1775
1776int google_chromeec_regulator_is_enabled(uint32_t index, uint8_t *enabled)
1777{
Yidi Lin99e6dd92020-10-23 16:02:59 +08001778 struct ec_params_regulator_is_enabled params = {
1779 .index = index,
1780 };
1781 struct ec_response_regulator_is_enabled resp = {};
1782 struct chromeec_command cmd = {
1783 .cmd_code = EC_CMD_REGULATOR_IS_ENABLED,
1784 .cmd_version = 0,
1785 .cmd_data_in = &params,
1786 .cmd_size_in = sizeof(params),
1787 .cmd_data_out = &resp,
1788 .cmd_size_out = sizeof(resp),
1789 .cmd_dev_index = 0,
1790 };
1791
1792 if (google_chromeec_command(&cmd))
1793 return -1;
1794
1795 *enabled = resp.enabled;
1796
1797 return 0;
1798}
1799
Yidi Lin79a812e2020-09-21 20:25:54 +08001800int google_chromeec_regulator_set_voltage(uint32_t index, uint32_t min_mv,
1801 uint32_t max_mv)
1802{
1803 struct ec_params_regulator_set_voltage params = {
1804 .index = index,
1805 .min_mv = min_mv,
1806 .max_mv = max_mv,
1807 };
1808 struct chromeec_command cmd = {
1809 .cmd_code = EC_CMD_REGULATOR_SET_VOLTAGE,
1810 .cmd_version = 0,
1811 .cmd_data_in = &params,
1812 .cmd_size_in = sizeof(params),
1813 .cmd_data_out = NULL,
1814 .cmd_size_out = 0,
1815 .cmd_dev_index = 0,
1816 };
1817
1818 if (google_chromeec_command(&cmd))
1819 return -1;
1820
1821 return 0;
1822}
1823
1824int google_chromeec_regulator_get_voltage(uint32_t index, uint32_t *voltage_mv)
1825{
1826 struct ec_params_regulator_get_voltage params = {
1827 .index = index,
1828 };
1829 struct ec_response_regulator_get_voltage resp = {};
1830 struct chromeec_command cmd = {
1831 .cmd_code = EC_CMD_REGULATOR_GET_VOLTAGE,
1832 .cmd_version = 0,
1833 .cmd_data_in = &params,
1834 .cmd_size_in = sizeof(params),
1835 .cmd_data_out = &resp,
1836 .cmd_size_out = sizeof(resp),
1837 .cmd_dev_index = 0,
1838 };
1839
1840 if (google_chromeec_command(&cmd))
1841 return -1;
1842
1843 *voltage_mv = resp.voltage_mv;
1844 return 0;
1845}