blob: 57c1b58121d03a99f313da5b85270e37bb7d4e73 [file] [log] [blame]
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Stefan Reinauerd6682e82013-02-21 15:39:35 -080014 */
15
16#include <stdint.h>
Stefan Reinaueraaaf6892013-08-29 15:57:11 -070017#include <string.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080018#include <cbmem.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080019#include <console/console.h>
Jenny TC1dfc2c32017-12-14 14:24:39 +053020#include <arch/early_variables.h>
Jenny TC1dfc2c32017-12-14 14:24:39 +053021#include <assert.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080022#include <bootmode.h>
23#include <bootstate.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080024#include <delay.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080025#include <elog.h>
Duncan Laurie7cced0d2013-06-04 10:03:34 -070026#include <reset.h>
Simon Glass78659322016-06-10 20:58:24 -060027#include <rtc.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080028#include <stdlib.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020029#include <security/vboot/vboot_common.h>
Daisuke Nojiriebb86be2018-01-26 17:36:44 -080030#include <timer.h>
Edward O'Callaghanb57fef92014-06-17 20:13:08 +100031
Stefan Reinauerd6682e82013-02-21 15:39:35 -080032#include "chip.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080033#include "ec.h"
34#include "ec_commands.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080035
Jenny TC1dfc2c32017-12-14 14:24:39 +053036#define INVALID_HCMD 0xFF
37
38/*
39 * Map UHEPI masks to non UHEPI commands in order to support old EC FW
40 * which does not support UHEPI command.
41 */
42static const struct {
43 uint8_t set_cmd;
44 uint8_t clear_cmd;
45 uint8_t get_cmd;
46} event_map[] = {
47 [EC_HOST_EVENT_MAIN] = {
48 INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR,
49 INVALID_HCMD,
50 },
51 [EC_HOST_EVENT_B] = {
52 INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR_B,
53 EC_CMD_HOST_EVENT_GET_B,
54 },
55 [EC_HOST_EVENT_SCI_MASK] = {
56 EC_CMD_HOST_EVENT_SET_SCI_MASK, INVALID_HCMD,
57 EC_CMD_HOST_EVENT_GET_SCI_MASK,
58 },
59 [EC_HOST_EVENT_SMI_MASK] = {
60 EC_CMD_HOST_EVENT_SET_SMI_MASK, INVALID_HCMD,
61 EC_CMD_HOST_EVENT_GET_SMI_MASK,
62 },
63 [EC_HOST_EVENT_ALWAYS_REPORT_MASK] = {
64 INVALID_HCMD, INVALID_HCMD, INVALID_HCMD,
65 },
66 [EC_HOST_EVENT_ACTIVE_WAKE_MASK] = {
67 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
68 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
69 },
Patrick Georgia29d2342018-05-02 17:12:49 +020070 [EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX] = {
71 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
72 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
73 },
74 [EC_HOST_EVENT_LAZY_WAKE_MASK_S3] = {
75 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
76 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
77 },
78 [EC_HOST_EVENT_LAZY_WAKE_MASK_S5] = {
79 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
80 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
81 },
Jenny TC1dfc2c32017-12-14 14:24:39 +053082};
83
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080084void log_recovery_mode_switch(void)
85{
Furquan Shaikh8788fd62017-11-20 20:28:18 -080086 uint64_t *events;
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080087
88 if (cbmem_find(CBMEM_ID_EC_HOSTEVENT))
89 return;
90
91 events = cbmem_add(CBMEM_ID_EC_HOSTEVENT, sizeof(*events));
92 if (!events)
93 return;
94
95 *events = google_chromeec_get_events_b();
96}
97
98static void google_chromeec_elog_add_recovery_event(void *unused)
99{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800100 uint64_t *events = cbmem_find(CBMEM_ID_EC_HOSTEVENT);
Furquan Shaikhbce8bb62016-11-11 13:57:55 -0800101 uint8_t event_byte = EC_EVENT_KEYBOARD_RECOVERY;
102
103 if (!events)
104 return;
105
106 if (!(*events & EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY)))
107 return;
108
109 if (*events &
110 EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT))
111 event_byte = EC_EVENT_KEYBOARD_RECOVERY_HWREINIT;
112
113 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event_byte);
114}
115
116BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
117 google_chromeec_elog_add_recovery_event, NULL);
118
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800119uint8_t google_chromeec_calc_checksum(const uint8_t *data, int size)
120{
121 int csum;
122
123 for (csum = 0; size > 0; data++, size--)
124 csum += *data;
125 return (uint8_t)(csum & 0xff);
126}
127
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800128int google_chromeec_kbbacklight(int percent)
129{
130 struct chromeec_command cec_cmd;
131 struct ec_params_pwm_set_keyboard_backlight cmd_backlight;
132 struct ec_response_pwm_get_keyboard_backlight rsp_backlight;
133 /* if they were dumb, help them out */
134 percent = percent % 101;
135 cec_cmd.cmd_code = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
136 cec_cmd.cmd_version = 0;
137 cmd_backlight.percent = percent;
138 cec_cmd.cmd_data_in = &cmd_backlight;
139 cec_cmd.cmd_data_out = &rsp_backlight;
140 cec_cmd.cmd_size_in = sizeof(cmd_backlight);
141 cec_cmd.cmd_size_out = sizeof(rsp_backlight);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700142 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800143 google_chromeec_command(&cec_cmd);
144 printk(BIOS_DEBUG, "Google Chrome set keyboard backlight: %x status (%x)\n",
145 rsp_backlight.percent, cec_cmd.cmd_code);
146 return cec_cmd.cmd_code;
147
148}
149
150void google_chromeec_post(u8 postcode)
151{
152 /* backlight is a percent. postcode is a u8.
153 * Convert the u8 to %.
154 */
155 postcode = (postcode/4) + (postcode/8);
156 google_chromeec_kbbacklight(postcode);
157}
158
159/*
160 * Query the EC for specified mask indicating enabled events.
161 * The EC maintains separate event masks for SMI, SCI and WAKE.
162 */
Jenny TC1dfc2c32017-12-14 14:24:39 +0530163static int google_chromeec_uhepi_cmd(uint8_t mask, uint8_t action,
164 uint64_t *value)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800165{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530166 int ret;
167 struct ec_params_host_event req;
168 struct ec_response_host_event rsp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800169 struct chromeec_command cmd;
170
Jenny TC1dfc2c32017-12-14 14:24:39 +0530171 req.action = action;
172 req.mask_type = mask;
173 if (action != EC_HOST_EVENT_GET)
174 req.value = *value;
175 else
176 *value = 0;
177 cmd.cmd_code = EC_CMD_HOST_EVENT;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800178 cmd.cmd_version = 0;
179 cmd.cmd_data_in = &req;
180 cmd.cmd_size_in = sizeof(req);
181 cmd.cmd_data_out = &rsp;
182 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700183 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800184
Jenny TC1dfc2c32017-12-14 14:24:39 +0530185 ret = google_chromeec_command(&cmd);
186
187 if (action != EC_HOST_EVENT_GET)
188 return ret;
189 if (ret == 0)
190 *value = rsp.value;
191 return ret;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800192}
193
Jenny TC1dfc2c32017-12-14 14:24:39 +0530194static int google_chromeec_handle_non_uhepi_cmd(uint8_t hcmd, uint8_t action,
195 uint64_t *value)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700196{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530197 int ret = -1;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700198 struct ec_params_host_event_mask req;
199 struct ec_response_host_event_mask rsp;
200 struct chromeec_command cmd;
201
Jenny TC1dfc2c32017-12-14 14:24:39 +0530202 if (hcmd == INVALID_HCMD)
203 return ret;
204
205 if (action != EC_HOST_EVENT_GET)
206 req.mask = (uint32_t)*value;
207 else
208 *value = 0;
209
210 cmd.cmd_code = hcmd;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700211 cmd.cmd_version = 0;
212 cmd.cmd_data_in = &req;
213 cmd.cmd_size_in = sizeof(req);
214 cmd.cmd_data_out = &rsp;
215 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700216 cmd.cmd_dev_index = 0;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700217
Jenny TC1dfc2c32017-12-14 14:24:39 +0530218 ret = google_chromeec_command(&cmd);
219
220 if (action != EC_HOST_EVENT_GET)
221 return ret;
222 if (ret == 0)
223 *value = rsp.mask;
224
225 return ret;
226}
227
228bool google_chromeec_is_uhepi_supported(void)
229{
230#define UHEPI_SUPPORTED 1
231#define UHEPI_NOT_SUPPORTED 2
232
233 static int uhepi_support CAR_GLOBAL;
234
235 if (!uhepi_support) {
236 uhepi_support = google_chromeec_check_feature
Matt DeVillier41328932018-03-04 00:05:12 -0600237 (EC_FEATURE_UNIFIED_WAKE_MASKS) > 0 ? UHEPI_SUPPORTED :
Jenny TC1dfc2c32017-12-14 14:24:39 +0530238 UHEPI_NOT_SUPPORTED;
239 printk(BIOS_DEBUG, "Chrome EC: UHEPI %s\n",
240 uhepi_support == UHEPI_SUPPORTED ?
241 "supported" : "not supported");
242 }
243 return uhepi_support == UHEPI_SUPPORTED;
244}
245
246static uint64_t google_chromeec_get_mask(u8 type)
247{
248 u64 value = 0;
249
250 if (google_chromeec_is_uhepi_supported()) {
251 google_chromeec_uhepi_cmd(type, EC_HOST_EVENT_GET, &value);
252 } else {
253 assert(type < ARRAY_SIZE(event_map));
254 google_chromeec_handle_non_uhepi_cmd(
255 event_map[type].get_cmd,
256 EC_HOST_EVENT_GET, &value);
257 }
258 return value;
259}
260static int google_chromeec_clear_mask(u8 type, u64 mask)
261{
262 if (google_chromeec_is_uhepi_supported())
263 return google_chromeec_uhepi_cmd(type,
264 EC_HOST_EVENT_CLEAR, &mask);
265
266 assert(type < ARRAY_SIZE(event_map));
267 return google_chromeec_handle_non_uhepi_cmd(
268 event_map[type].clear_cmd,
269 EC_HOST_EVENT_CLEAR, &mask);
270}
271static int __unused google_chromeec_set_mask(u8 type, u64 mask)
272{
273 if (google_chromeec_is_uhepi_supported())
274 return google_chromeec_uhepi_cmd(type,
275 EC_HOST_EVENT_SET, &mask);
276
277 assert(type < ARRAY_SIZE(event_map));
278 return google_chromeec_handle_non_uhepi_cmd(
279 event_map[type].set_cmd,
280 EC_HOST_EVENT_SET, &mask);
281}
282
283static int google_chromeec_set_s3_lazy_wake_mask(uint64_t mask)
284{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800285 printk(BIOS_DEBUG, "Chrome EC: Set S3 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530286 mask);
287 return google_chromeec_set_mask
288 (EC_HOST_EVENT_LAZY_WAKE_MASK_S3, mask);
289}
290
291static int google_chromeec_set_s5_lazy_wake_mask(uint64_t mask)
292{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800293 printk(BIOS_DEBUG, "Chrome EC: Set S5 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530294 mask);
295 return google_chromeec_set_mask
296 (EC_HOST_EVENT_LAZY_WAKE_MASK_S5, mask);
297}
298
299static int google_chromeec_set_s0ix_lazy_wake_mask(uint64_t mask)
300{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800301 printk(BIOS_DEBUG, "Chrome EC: Set S0iX LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530302 mask);
303 return google_chromeec_set_mask
304 (EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, mask);
305}
306static void google_chromeec_set_lazy_wake_masks(uint64_t s5_mask,
307 uint64_t s3_mask, uint64_t s0ix_mask)
308{
309 if (google_chromeec_set_s5_lazy_wake_mask(s5_mask))
310 printk(BIOS_DEBUG, "Error: Set S5 LAZY WAKE mask failed\n");
311 if (google_chromeec_set_s3_lazy_wake_mask(s3_mask))
312 printk(BIOS_DEBUG, "Error: Set S3 LAZY WAKE mask failed\n");
Paul Moy88900dc2018-09-14 15:24:23 -0600313 /*
314 * Make sure S0Ix is supported before trying to set up the EC's
315 * S0Ix lazy wake mask.
316 */
317 if (s0ix_mask && google_chromeec_set_s0ix_lazy_wake_mask(s0ix_mask))
Jenny TC1dfc2c32017-12-14 14:24:39 +0530318 printk(BIOS_DEBUG, "Error: Set S0iX LAZY WAKE mask failed\n");
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700319}
320
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800321uint64_t google_chromeec_get_events_b(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800322{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530323 return google_chromeec_get_mask(EC_HOST_EVENT_B);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800324}
325
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800326int google_chromeec_clear_events_b(uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700327{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530328 printk(BIOS_DEBUG,
329 "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
330 return google_chromeec_clear_mask(EC_HOST_EVENT_B, mask);
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700331}
332
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700333int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
334{
335 struct chromeec_command cmd;
336
337 cmd.cmd_code = EC_CMD_GET_NEXT_EVENT;
338 cmd.cmd_version = 0;
339 cmd.cmd_data_in = NULL;
340 cmd.cmd_size_in = 0;
341 cmd.cmd_data_out = event;
342 cmd.cmd_size_out = sizeof(*event);
343 cmd.cmd_dev_index = 0;
344
345 return google_chromeec_command(&cmd);
346}
347
Duncan Laurie7378a172017-06-29 23:52:17 -0700348/* Get the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800349uint64_t google_chromeec_get_device_enabled_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700350{
351 struct ec_params_device_event req;
352 struct ec_response_device_event rsp;
353 struct chromeec_command cmd;
354
355 req.param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS;
356 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
357 cmd.cmd_version = 0;
358 cmd.cmd_data_in = &req;
359 cmd.cmd_size_in = sizeof(req);
360 cmd.cmd_data_out = &rsp;
361 cmd.cmd_size_out = sizeof(rsp);
362 cmd.cmd_dev_index = 0;
363
364 if (google_chromeec_command(&cmd) == 0)
365 return rsp.event_mask;
366 return 0;
367}
368
369/* Set the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800370int google_chromeec_set_device_enabled_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700371{
372 struct ec_params_device_event req;
373 struct ec_response_device_event rsp;
374 struct chromeec_command cmd;
375
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800376 req.event_mask = (uint32_t)mask;
Duncan Laurie7378a172017-06-29 23:52:17 -0700377 req.param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS;
378 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
379 cmd.cmd_version = 0;
380 cmd.cmd_data_in = &req;
381 cmd.cmd_size_in = sizeof(req);
382 cmd.cmd_data_out = &rsp;
383 cmd.cmd_size_out = sizeof(rsp);
384 cmd.cmd_dev_index = 0;
385
386 return google_chromeec_command(&cmd);
387}
388
389/* Read and clear pending device events */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800390uint64_t google_chromeec_get_device_current_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700391{
392 struct ec_params_device_event req;
393 struct ec_response_device_event rsp;
394 struct chromeec_command cmd;
395
396 req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
397 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
398 cmd.cmd_version = 0;
399 cmd.cmd_data_in = &req;
400 cmd.cmd_size_in = sizeof(req);
401 cmd.cmd_data_out = &rsp;
402 cmd.cmd_size_out = sizeof(rsp);
403 cmd.cmd_dev_index = 0;
404
405 if (google_chromeec_command(&cmd) == 0)
406 return rsp.event_mask;
407 return 0;
408}
409
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800410static void google_chromeec_log_device_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700411{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800412 uint64_t events;
Duncan Laurie7378a172017-06-29 23:52:17 -0700413 int i;
414
Julius Wernercd49cce2019-03-05 16:53:33 -0800415 if (!CONFIG(ELOG) || !mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700416 return;
417
418 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
419 return;
420
421 events = google_chromeec_get_device_current_events() & mask;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800422 printk(BIOS_INFO, "EC Device Events: 0x%016llx\n", events);
Duncan Laurie7378a172017-06-29 23:52:17 -0700423
424 for (i = 0; i < sizeof(events) * 8; i++) {
425 if (EC_DEVICE_EVENT_MASK(i) & events)
426 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
427 }
428}
429
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800430void google_chromeec_log_events(uint64_t mask)
Furquan Shaikh2749c522017-10-04 14:01:41 -0700431{
432 u8 event;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800433 uint64_t wake_mask;
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700434 bool restore_wake_mask = false;
Furquan Shaikh2749c522017-10-04 14:01:41 -0700435
Julius Wernercd49cce2019-03-05 16:53:33 -0800436 if (!CONFIG(ELOG))
Furquan Shaikh2749c522017-10-04 14:01:41 -0700437 return;
438
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700439 /*
440 * If the EC supports unified wake masks, then there is no need to set
441 * wake mask before reading out the host events.
442 */
443 if (google_chromeec_check_feature(EC_FEATURE_UNIFIED_WAKE_MASKS) != 1) {
444 wake_mask = google_chromeec_get_wake_mask();
445 google_chromeec_set_wake_mask(mask);
446 restore_wake_mask = true;
447 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700448
449 while ((event = google_chromeec_get_event()) != 0) {
450 if (EC_HOST_EVENT_MASK(event) & mask)
451 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event);
452 }
453
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700454 if (restore_wake_mask)
455 google_chromeec_set_wake_mask(wake_mask);
Furquan Shaikh2749c522017-10-04 14:01:41 -0700456}
457
458void google_chromeec_events_init(const struct google_chromeec_event_info *info,
459 bool is_s3_wakeup)
460{
461 if (is_s3_wakeup) {
462 google_chromeec_log_events(info->log_events |
463 info->s3_wake_events);
464
465 /* Log and clear device events that may wake the system. */
466 google_chromeec_log_device_events(info->s3_device_events);
467
468 /* Disable SMI and wake events. */
469 google_chromeec_set_smi_mask(0);
470
471 /* Clear pending events. */
472 while (google_chromeec_get_event() != 0)
473 ;
474
475 /* Restore SCI event mask. */
476 google_chromeec_set_sci_mask(info->sci_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530477
478 } else {
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700479 google_chromeec_set_smi_mask(info->smi_events);
480
Furquan Shaikh2749c522017-10-04 14:01:41 -0700481 google_chromeec_log_events(info->log_events |
482 info->s5_wake_events);
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700483
Jenny TC1dfc2c32017-12-14 14:24:39 +0530484 if (google_chromeec_is_uhepi_supported())
485 google_chromeec_set_lazy_wake_masks
486 (info->s5_wake_events,
487 info->s3_wake_events,
488 info->s0ix_wake_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530489 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700490
491 /* Clear wake event mask. */
492 google_chromeec_set_wake_mask(0);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530493
Furquan Shaikh2749c522017-10-04 14:01:41 -0700494}
495
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800496int google_chromeec_check_feature(int feature)
497{
498 struct chromeec_command cmd;
499 struct ec_response_get_features r;
500
501 cmd.cmd_code = EC_CMD_GET_FEATURES;
502 cmd.cmd_version = 0;
503 cmd.cmd_size_in = 0;
504 cmd.cmd_data_out = &r;
505 cmd.cmd_size_out = sizeof(r);
506 cmd.cmd_dev_index = 0;
507
508 if (google_chromeec_command(&cmd) != 0)
509 return -1;
510
511 if (feature >= 8 * sizeof(r.flags))
512 return -1;
513
514 return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
515}
516
Kevin Chiue2bb0592017-09-12 09:13:41 +0800517int google_chromeec_set_sku_id(u32 skuid)
518{
519 struct chromeec_command cmd;
520 struct ec_sku_id_info set_skuid = {
521 .sku_id = skuid
522 };
523
524 cmd.cmd_code = EC_CMD_SET_SKU_ID;
525 cmd.cmd_version = 0;
526 cmd.cmd_size_in = sizeof(set_skuid);
527 cmd.cmd_data_in = &set_skuid;
528 cmd.cmd_data_out = NULL;
529 cmd.cmd_size_out = 0;
530 cmd.cmd_dev_index = 0;
531
532 if (google_chromeec_command(&cmd) != 0)
533 return -1;
534
535 return 0;
536}
537
Julius Wernercd49cce2019-03-05 16:53:33 -0800538#if CONFIG(EC_GOOGLE_CHROMEEC_RTC)
Simon Glass78659322016-06-10 20:58:24 -0600539int rtc_get(struct rtc_time *time)
540{
541 struct chromeec_command cmd;
542 struct ec_response_rtc r;
543
544 cmd.cmd_code = EC_CMD_RTC_GET_VALUE;
545 cmd.cmd_version = 0;
546 cmd.cmd_size_in = 0;
547 cmd.cmd_data_out = &r;
548 cmd.cmd_size_out = sizeof(r);
549 cmd.cmd_dev_index = 0;
550
551 if (google_chromeec_command(&cmd) != 0)
552 return -1;
553
554 return rtc_to_tm(r.time, time);
555}
556#endif
557
Aaron Durbine68d22f2017-05-04 12:32:52 -0500558int google_chromeec_reboot(int dev_idx, enum ec_reboot_cmd type, uint8_t flags)
559{
560 struct ec_params_reboot_ec reboot_ec = {
561 .cmd = type,
562 .flags = flags,
563 };
564 struct ec_response_get_version cec_resp = { };
565 struct chromeec_command cec_cmd = {
566 .cmd_code = EC_CMD_REBOOT_EC,
567 .cmd_version = 0,
568 .cmd_data_in = &reboot_ec,
569 .cmd_data_out = &cec_resp,
570 .cmd_size_in = sizeof(reboot_ec),
571 .cmd_size_out = 0, /* ignore response, if any */
572 .cmd_dev_index = dev_idx,
573 };
574
575 return google_chromeec_command(&cec_cmd);
576}
577
Jonathan Brandmeyer6bffc5c2018-07-23 16:30:44 -0600578static int cbi_get_uint32(uint32_t *id, uint32_t tag)
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800579{
580 struct chromeec_command cmd;
581 struct ec_params_get_cbi p;
Zhuohao Lee7824d9b2018-03-30 10:18:04 +0800582 uint32_t r = 0;
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800583 int rv;
584
Jonathan Brandmeyer6bffc5c2018-07-23 16:30:44 -0600585 p.tag = tag;
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800586
587 cmd.cmd_code = EC_CMD_GET_CROS_BOARD_INFO;
588 cmd.cmd_version = 0;
589 cmd.cmd_data_in = &p;
590 cmd.cmd_data_out = &r;
591 cmd.cmd_size_in = sizeof(p);
592 cmd.cmd_size_out = sizeof(r);
593 cmd.cmd_dev_index = 0;
594
595 rv = google_chromeec_command(&cmd);
YH Lin40f65422019-02-26 09:56:06 -0800596 if (rv != 0)
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800597 return rv;
598 *id = r;
599 return 0;
600}
601
602int google_chromeec_cbi_get_sku_id(uint32_t *id)
603{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800604 return cbi_get_uint32(id, CBI_TAG_SKU_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800605}
606
607int google_chromeec_cbi_get_oem_id(uint32_t *id)
608{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800609 return cbi_get_uint32(id, CBI_TAG_OEM_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800610}
611
Wisley Chenc1efec72018-11-06 09:28:23 +0800612static int cbi_get_string(char *buf, size_t bufsize, uint32_t tag)
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600613{
614 struct ec_params_get_cbi p = {
Wisley Chenc1efec72018-11-06 09:28:23 +0800615 .tag = tag,
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600616 };
617 struct chromeec_command cmd = {
618 .cmd_code = EC_CMD_GET_CROS_BOARD_INFO,
619 .cmd_version = 0,
620 .cmd_data_in = &p,
621 .cmd_data_out = buf,
622 .cmd_size_in = sizeof(p),
623 .cmd_size_out = bufsize,
624 };
625 int rv;
626
627 rv = google_chromeec_command(&cmd);
YH Lin40f65422019-02-26 09:56:06 -0800628 if (rv != 0)
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600629 return rv;
630
631 /* Ensure NUL termination. */
632 buf[bufsize - 1] = '\0';
633
634 return 0;
635}
636
Wisley Chenc1efec72018-11-06 09:28:23 +0800637int google_chromeec_cbi_get_dram_part_num(char *buf, size_t bufsize)
638{
639 return cbi_get_string(buf, bufsize, CBI_TAG_DRAM_PART_NUM);
640}
641
642int google_chromeec_cbi_get_oem_name(char *buf, size_t bufsize)
643{
644 return cbi_get_string(buf, bufsize, CBI_TAG_OEM_NAME);
645}
646
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600647int google_chromeec_get_board_version(uint32_t *version)
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700648{
649 struct chromeec_command cmd;
650 struct ec_response_board_version board_v;
651
652 cmd.cmd_code = EC_CMD_GET_BOARD_VERSION;
653 cmd.cmd_version = 0;
654 cmd.cmd_size_in = 0;
655 cmd.cmd_size_out = sizeof(board_v);
656 cmd.cmd_data_out = &board_v;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700657 cmd.cmd_dev_index = 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700658
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600659 if (google_chromeec_command(&cmd))
660 return -1;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700661
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600662 *version = board_v.board_version;
663 return 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700664}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700665
Patrick Georgi69206d92017-07-31 14:20:07 +0200666u32 google_chromeec_get_sku_id(void)
667{
668 struct chromeec_command cmd;
Kevin Chiue2bb0592017-09-12 09:13:41 +0800669 struct ec_sku_id_info sku_v;
Patrick Georgi69206d92017-07-31 14:20:07 +0200670
671 cmd.cmd_code = EC_CMD_GET_SKU_ID;
672 cmd.cmd_version = 0;
673 cmd.cmd_size_in = 0;
674 cmd.cmd_size_out = sizeof(sku_v);
675 cmd.cmd_data_out = &sku_v;
676 cmd.cmd_dev_index = 0;
677
678 if (google_chromeec_command(&cmd) != 0)
679 return 0;
680
681 return sku_v.sku_id;
682}
683
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700684int google_chromeec_vbnv_context(int is_read, uint8_t *data, int len)
685{
686 struct chromeec_command cec_cmd;
687 struct ec_params_vbnvcontext cmd_vbnvcontext;
688 struct ec_response_vbnvcontext rsp_vbnvcontext;
Julius Werner02e847b2015-02-20 13:36:11 -0800689 int retries = 3;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700690
691 if (len != EC_VBNV_BLOCK_SIZE)
692 return -1;
693
Patrick Georgif5060312015-10-13 22:14:22 +0200694retry:
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700695 cec_cmd.cmd_code = EC_CMD_VBNV_CONTEXT;
696 cec_cmd.cmd_version = EC_VER_VBNV_CONTEXT;
697 cec_cmd.cmd_data_in = &cmd_vbnvcontext;
698 cec_cmd.cmd_data_out = &rsp_vbnvcontext;
699 cec_cmd.cmd_size_in = sizeof(cmd_vbnvcontext);
Aaron Durbin3e497382014-08-06 14:28:52 -0500700 cec_cmd.cmd_size_out = is_read ? sizeof(rsp_vbnvcontext) : 0;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700701 cec_cmd.cmd_dev_index = 0;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700702
703 cmd_vbnvcontext.op = is_read ? EC_VBNV_CONTEXT_OP_READ :
704 EC_VBNV_CONTEXT_OP_WRITE;
705
706 if (!is_read)
707 memcpy(&cmd_vbnvcontext.block, data, EC_VBNV_BLOCK_SIZE);
708
Julius Werner02e847b2015-02-20 13:36:11 -0800709 if (google_chromeec_command(&cec_cmd)) {
710 printk(BIOS_ERR, "ERROR: failed to %s vbnv_ec context: %d\n",
711 is_read ? "read" : "write", (int)cec_cmd.cmd_code);
712 mdelay(10); /* just in case */
713 if (--retries)
714 goto retry;
715 }
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700716
717 if (is_read)
718 memcpy(data, &rsp_vbnvcontext.block, EC_VBNV_BLOCK_SIZE);
719
720 return cec_cmd.cmd_code;
721}
722
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800723#ifndef __PRE_RAM__
724
Gabe Black9f96aa62013-06-28 14:24:33 -0700725int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
726 uint8_t *buffer, int len, int is_read)
727{
728 union {
729 struct ec_params_i2c_passthru p;
730 uint8_t outbuf[EC_HOST_PARAM_SIZE];
731 } params;
732 union {
733 struct ec_response_i2c_passthru r;
734 uint8_t inbuf[EC_HOST_PARAM_SIZE];
735 } response;
736 struct ec_params_i2c_passthru *p = &params.p;
737 struct ec_response_i2c_passthru *r = &response.r;
738 struct ec_params_i2c_passthru_msg *msg = p->msg;
739 struct chromeec_command cmd;
740 uint8_t *pdata;
741 int read_len, write_len;
742 int size;
743 int rv;
744
745 p->port = 0;
746
747 if (alen != 1) {
748 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
749 return -1;
750 }
751 if (is_read) {
752 read_len = len;
753 write_len = alen;
754 p->num_msgs = 2;
755 } else {
756 read_len = 0;
757 write_len = alen + len;
758 p->num_msgs = 1;
759 }
760
761 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
762 if (size + write_len > sizeof(params)) {
763 printk(BIOS_ERR, "Params too large for buffer\n");
764 return -1;
765 }
766 if (sizeof(*r) + read_len > sizeof(response)) {
767 printk(BIOS_ERR, "Read length too big for buffer\n");
768 return -1;
769 }
770
771 /* Create a message to write the register address and optional data */
772 pdata = (uint8_t *)p + size;
773 msg->addr_flags = chip;
774 msg->len = write_len;
775 pdata[0] = addr;
776 if (!is_read)
777 memcpy(pdata + 1, buffer, len);
778 msg++;
779
780 if (read_len) {
781 msg->addr_flags = chip | EC_I2C_FLAG_READ;
782 msg->len = read_len;
783 }
784
785 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
786 cmd.cmd_version = 0;
787 cmd.cmd_data_in = p;
788 cmd.cmd_size_in = size + write_len;
789 cmd.cmd_data_out = r;
790 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700791 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -0700792 rv = google_chromeec_command(&cmd);
793 if (rv != 0)
794 return rv;
795
796 /* Parse response */
797 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
798 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
799 r->i2c_status);
800 return -1;
801 }
802
803 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
804 printk(BIOS_ERR, "Truncated read response\n");
805 return -1;
806 }
807
808 if (read_len)
809 memcpy(buffer, r->data, read_len);
810
811 return 0;
812}
813
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800814int google_chromeec_set_sci_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800815{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800816 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530817 return google_chromeec_set_mask(EC_HOST_EVENT_SCI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800818}
819
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800820int google_chromeec_set_smi_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800821{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800822 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530823 return google_chromeec_set_mask(EC_HOST_EVENT_SMI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800824}
825
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800826int google_chromeec_set_wake_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800827{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800828 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530829 return google_chromeec_set_mask
830 (EC_HOST_EVENT_ACTIVE_WAKE_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800831}
832
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800833uint64_t google_chromeec_get_wake_mask(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800834{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530835 return google_chromeec_get_mask(EC_HOST_EVENT_ACTIVE_WAKE_MASK);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800836}
837
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800838int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode)
839{
840 struct chromeec_command cmd;
841 struct ec_params_usb_charge_set_mode set_mode = {
842 .usb_port_id = port_id,
843 .mode = mode,
844 };
845
846 cmd.cmd_code = EC_CMD_USB_CHARGE_SET_MODE;
847 cmd.cmd_version = 0;
848 cmd.cmd_size_in = sizeof(set_mode);
849 cmd.cmd_data_in = &set_mode;
850 cmd.cmd_size_out = 0;
851 cmd.cmd_data_out = NULL;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700852 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800853
854 return google_chromeec_command(&cmd);
855}
856
Shelley Chenebd53302017-09-29 14:15:11 -0700857/* Get charger power info in Watts. Also returns type of charger */
858int google_chromeec_get_usb_pd_power_info(enum usb_chg_type *type,
859 u32 *max_watts)
860{
861 struct ec_params_usb_pd_power_info req = {
862 .port = PD_POWER_CHARGING_PORT,
863 };
864 struct ec_response_usb_pd_power_info rsp;
865 struct chromeec_command cmd = {
866 .cmd_code = EC_CMD_USB_PD_POWER_INFO,
867 .cmd_version = 0,
868 .cmd_data_in = &req,
869 .cmd_size_in = sizeof(req),
870 .cmd_data_out = &rsp,
871 .cmd_size_out = sizeof(rsp),
872 .cmd_dev_index = 0,
873 };
874 struct usb_chg_measures m;
875 int rv = google_chromeec_command(&cmd);
876 if (rv != 0)
877 return rv;
878 /* values are given in milliAmps and milliVolts */
879 *type = rsp.type;
880 m = rsp.meas;
881 *max_watts = (m.current_max * m.voltage_max) / 1000000;
882
883 return 0;
884}
885
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800886int google_chromeec_override_dedicated_charger_limit(u16 current_lim,
887 u16 voltage_lim)
888{
889 struct ec_params_dedicated_charger_limit p = {
890 .current_lim = current_lim,
891 .voltage_lim = voltage_lim,
892 };
893 struct chromeec_command cmd = {
894 .cmd_code = EC_CMD_OVERRIDE_DEDICATED_CHARGER_LIMIT,
895 .cmd_version = 0,
896 .cmd_data_in = &p,
897 .cmd_size_in = sizeof(p),
898 .cmd_data_out = NULL,
899 .cmd_size_out = 0,
900 .cmd_dev_index = 0,
901 };
902
903 return google_chromeec_command(&cmd);
904}
905
Julius Wernerea79d2b2016-11-21 20:14:07 -0800906int google_chromeec_set_usb_pd_role(u8 port, enum usb_pd_control_role role)
907{
908 struct ec_params_usb_pd_control req = {
909 .port = port,
910 .role = role,
911 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
912 .swap = USB_PD_CTRL_SWAP_NONE,
913 };
914 struct ec_response_usb_pd_control rsp;
915 struct chromeec_command cmd = {
916 .cmd_code = EC_CMD_USB_PD_CONTROL,
917 .cmd_version = 0,
918 .cmd_data_in = &req,
919 .cmd_size_in = sizeof(req),
920 .cmd_data_out = &rsp,
921 .cmd_size_out = sizeof(rsp),
922 .cmd_dev_index = 0,
923 };
924
925 return google_chromeec_command(&cmd);
926}
927
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -0600928static int google_chromeec_hello(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800929{
930 struct chromeec_command cec_cmd;
931 struct ec_params_hello cmd_hello;
932 struct ec_response_hello rsp_hello;
933 cmd_hello.in_data = 0x10203040;
934 cec_cmd.cmd_code = EC_CMD_HELLO;
935 cec_cmd.cmd_version = 0;
936 cec_cmd.cmd_data_in = &cmd_hello.in_data;
937 cec_cmd.cmd_data_out = &rsp_hello.out_data;
938 cec_cmd.cmd_size_in = sizeof(cmd_hello.in_data);
939 cec_cmd.cmd_size_out = sizeof(rsp_hello.out_data);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700940 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800941 google_chromeec_command(&cec_cmd);
942 printk(BIOS_DEBUG, "Google Chrome EC: Hello got back %x status (%x)\n",
943 rsp_hello.out_data, cec_cmd.cmd_code);
944 return cec_cmd.cmd_code;
945}
946
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -0600947/*
948 * Convert a reset cause ID to human-readable string, providing total coverage
949 * of the 'cause' space. The returned string points to static storage and must
950 * not be free()ed.
951 */
952static const char *reset_cause_to_str(uint16_t cause)
953{
954 /* See also ChromiumOS EC include/chipset.h for details. */
955 static const char * const reset_causes[] = {
956 "(reset unknown)",
957 "reset: board custom",
958 "reset: ap hang detected",
959 "reset: console command",
960 "reset: keyboard sysreset",
961 "reset: keyboard warm reboot",
962 "reset: debug warm reboot",
963 "reset: at AP's request",
964 "reset: during EC initialization",
965 };
966
967 static const size_t shutdown_cause_begin = 1 << 15;
968 static const char * const shutdown_causes[] = {
969 "shutdown: power failure",
970 "shutdown: during EC initialization",
971 "shutdown: board custom",
972 "shutdown: battery voltage startup inhibit",
973 "shutdown: power wait asserted",
974 "shutdown: critical battery",
975 "shutdown: by console command",
976 "shutdown: entering G3",
977 "shutdown: thermal",
978 "shutdown: power button",
979 };
980
981 if (cause < ARRAY_SIZE(reset_causes))
982 return reset_causes[cause];
983
984 if (cause < shutdown_cause_begin)
985 return "(reset unknown)";
986
987 if (cause < shutdown_cause_begin + ARRAY_SIZE(shutdown_causes))
988 return shutdown_causes[cause - shutdown_cause_begin];
989
990 return "(shutdown unknown)";
991}
992
993/*
994 * Copy the EC's information about resets of the AP and its own uptime for
995 * debugging purposes.
996 */
997static void google_chromeec_log_uptimeinfo(void)
998{
999 /* See also ChromiumOS EC include/system.h RESET_FLAG for details. */
1000 static const char * const reset_flag_strings[] = {
1001 "other",
1002 "reset-pin",
1003 "brownout",
1004 "power-on",
1005 "watchdog",
1006 "soft",
1007 "hibernate",
1008 "rtc-alarm",
1009 "wake-pin",
1010 "low-battery",
1011 "sysjump",
1012 "hard",
1013 "ap-off",
1014 "preserved",
1015 "usb-resume",
1016 "rdd",
1017 "rbox",
1018 "security"
1019 };
1020 struct ec_response_uptime_info cmd_resp;
1021 int i, flag, flag_count;
1022
1023 struct chromeec_command get_uptime_cmd = {
1024 .cmd_code = EC_CMD_GET_UPTIME_INFO,
1025 .cmd_version = 0,
1026 .cmd_data_in = NULL,
1027 .cmd_size_in = 0,
1028 .cmd_data_out = &cmd_resp,
1029 .cmd_size_out = sizeof(cmd_resp),
1030 .cmd_dev_index = 0,
1031 };
1032 google_chromeec_command(&get_uptime_cmd);
1033 if (get_uptime_cmd.cmd_code) {
1034 /*
1035 * Deliberately say nothing for EC's that don't support this
1036 * command
1037 */
1038 return;
1039 }
1040
1041 printk(BIOS_DEBUG, "Google Chrome EC uptime: %d.%03d seconds\n",
1042 cmd_resp.time_since_ec_boot_ms / MSECS_PER_SEC,
1043 cmd_resp.time_since_ec_boot_ms % MSECS_PER_SEC);
1044
1045 printk(BIOS_DEBUG, "Google Chrome AP resets since EC boot: %d\n",
1046 cmd_resp.ap_resets_since_ec_boot);
1047
1048 printk(BIOS_DEBUG, "Google Chrome most recent AP reset causes:\n");
1049 for (i = 0; i != ARRAY_SIZE(cmd_resp.recent_ap_reset); ++i) {
1050 if (cmd_resp.recent_ap_reset[i].reset_time_ms == 0)
1051 continue;
1052
1053 printk(BIOS_DEBUG, "\t%d.%03d: %d %s\n",
1054 cmd_resp.recent_ap_reset[i].reset_time_ms /
1055 MSECS_PER_SEC,
1056 cmd_resp.recent_ap_reset[i].reset_time_ms %
1057 MSECS_PER_SEC,
1058 cmd_resp.recent_ap_reset[i].reset_cause,
1059 reset_cause_to_str(
1060 cmd_resp.recent_ap_reset[i].reset_cause));
1061 }
1062
1063 printk(BIOS_DEBUG, "Google Chrome EC reset flags at last EC boot: ");
1064 flag_count = 0;
1065 for (flag = 0; flag != ARRAY_SIZE(reset_flag_strings); ++flag) {
1066 if ((cmd_resp.ec_reset_flags & (1 << flag)) != 0) {
1067 if (flag_count)
1068 printk(BIOS_DEBUG, " | ");
1069 printk(BIOS_DEBUG, reset_flag_strings[flag]);
1070 flag_count++;
1071 }
1072 }
1073 printk(BIOS_DEBUG, "\n");
1074}
1075
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001076static int ec_image_type; /* Cached EC image type (ro or rw). */
1077
Hung-Te Lin76720d02013-04-15 18:06:32 +08001078void google_chromeec_init(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001079{
1080 struct chromeec_command cec_cmd;
Hung-Te Lin76720d02013-04-15 18:06:32 +08001081 struct ec_response_get_version cec_resp = {{0}};
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001082
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001083 google_chromeec_hello();
1084
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001085 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
1086 cec_cmd.cmd_version = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +08001087 cec_cmd.cmd_data_out = &cec_resp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001088 cec_cmd.cmd_size_in = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +08001089 cec_cmd.cmd_size_out = sizeof(cec_resp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -07001090 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001091 google_chromeec_command(&cec_cmd);
1092
1093 if (cec_cmd.cmd_code) {
1094 printk(BIOS_DEBUG,
1095 "Google Chrome EC: version command failed!\n");
1096 } else {
1097 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Hung-Te Lin76720d02013-04-15 18:06:32 +08001098 printk(BIOS_DEBUG, " ro: %s\n", cec_resp.version_string_ro);
1099 printk(BIOS_DEBUG, " rw: %s\n", cec_resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001100 printk(BIOS_DEBUG, " running image: %d\n",
Hung-Te Lin76720d02013-04-15 18:06:32 +08001101 cec_resp.current_image);
1102 ec_image_type = cec_resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001103 }
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001104
1105 google_chromeec_log_uptimeinfo();
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001106}
1107
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001108int google_ec_running_ro(void)
1109{
1110 return (ec_image_type == EC_IMAGE_RO);
1111}
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001112
1113#endif /* ! __PRE_RAM__ */
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001114
1115/**
1116 * Check if EC/TCPM is in an alternate mode or not.
1117 *
1118 * @param svid SVID of the alternate mode to check
1119 * @return 0: Not in the mode. -1: Error. 1: Yes.
1120 */
1121int google_chromeec_pd_get_amode(uint16_t svid)
1122{
1123 struct ec_response_usb_pd_ports r;
1124 struct chromeec_command cmd;
1125 int i;
1126
1127 cmd.cmd_code = EC_CMD_USB_PD_PORTS;
1128 cmd.cmd_version = 0;
1129 cmd.cmd_data_in = NULL;
1130 cmd.cmd_size_in = 0;
1131 cmd.cmd_data_out = &r;
1132 cmd.cmd_size_out = sizeof(r);
1133 cmd.cmd_dev_index = 0;
1134 if (google_chromeec_command(&cmd) < 0)
1135 return -1;
1136
1137 for (i = 0; i < r.num_ports; i++) {
1138 struct ec_params_usb_pd_get_mode_request p;
1139 struct ec_params_usb_pd_get_mode_response res;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001140 int svid_idx = 0;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001141
1142 do {
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001143 /* Reset cmd in each iteration in case
1144 google_chromeec_command changes it. */
1145 p.port = i;
1146 p.svid_idx = svid_idx;
1147 cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE;
1148 cmd.cmd_version = 0;
1149 cmd.cmd_data_in = &p;
1150 cmd.cmd_size_in = sizeof(p);
1151 cmd.cmd_data_out = &res;
1152 cmd.cmd_size_out = sizeof(res);
1153 cmd.cmd_dev_index = 0;
1154
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001155 if (google_chromeec_command(&cmd) < 0)
1156 return -1;
1157 if (res.svid == svid)
1158 return 1;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001159 svid_idx++;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001160 } while (res.svid);
1161 }
1162
1163 return 0;
1164}
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001165
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001166
1167#define USB_SID_DISPLAYPORT 0xff01
1168
Daisuke Nojirid182b632018-02-16 17:50:06 -08001169/**
1170 * Wait for DisplayPort to be ready
1171 *
1172 * @param timeout Wait aborts after <timeout> ms.
1173 * @return 1: Success or 0: Timeout.
1174 */
1175int google_chromeec_wait_for_displayport(long timeout)
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001176{
1177 struct stopwatch sw;
1178
Daisuke Nojirid182b632018-02-16 17:50:06 -08001179 printk(BIOS_INFO, "Waiting for DisplayPort\n");
1180 stopwatch_init_msecs_expire(&sw, timeout);
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001181 while (google_chromeec_pd_get_amode(USB_SID_DISPLAYPORT) != 1) {
1182 if (stopwatch_expired(&sw)) {
1183 printk(BIOS_WARNING,
Daisuke Nojirid182b632018-02-16 17:50:06 -08001184 "DisplayPort not ready after %ldms. Abort.\n",
1185 timeout);
1186 return 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001187 }
1188 mdelay(200);
1189 }
Daisuke Nojirid182b632018-02-16 17:50:06 -08001190 printk(BIOS_INFO, "DisplayPort ready after %lu ms\n",
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001191 stopwatch_duration_msecs(&sw));
Daisuke Nojirid182b632018-02-16 17:50:06 -08001192
1193 return 1;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001194}