blob: 094f7ce9a5e07cbc6aa6d7d419d022f950516f9d [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>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080021#include <arch/io.h>
Jenny TC1dfc2c32017-12-14 14:24:39 +053022#include <assert.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080023#include <bootmode.h>
24#include <bootstate.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080025#include <delay.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080026#include <elog.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010027#include <halt.h>
Duncan Laurie7cced0d2013-06-04 10:03:34 -070028#include <reset.h>
Simon Glass78659322016-06-10 20:58:24 -060029#include <rtc.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080030#include <stdlib.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020031#include <security/vboot/vboot_common.h>
Daisuke Nojiriebb86be2018-01-26 17:36:44 -080032#include <timer.h>
Edward O'Callaghanb57fef92014-06-17 20:13:08 +100033
Stefan Reinauerd6682e82013-02-21 15:39:35 -080034#include "chip.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080035#include "ec.h"
36#include "ec_commands.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080037
Jenny TC1dfc2c32017-12-14 14:24:39 +053038#define INVALID_HCMD 0xFF
39
40/*
41 * Map UHEPI masks to non UHEPI commands in order to support old EC FW
42 * which does not support UHEPI command.
43 */
44static const struct {
45 uint8_t set_cmd;
46 uint8_t clear_cmd;
47 uint8_t get_cmd;
48} event_map[] = {
49 [EC_HOST_EVENT_MAIN] = {
50 INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR,
51 INVALID_HCMD,
52 },
53 [EC_HOST_EVENT_B] = {
54 INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR_B,
55 EC_CMD_HOST_EVENT_GET_B,
56 },
57 [EC_HOST_EVENT_SCI_MASK] = {
58 EC_CMD_HOST_EVENT_SET_SCI_MASK, INVALID_HCMD,
59 EC_CMD_HOST_EVENT_GET_SCI_MASK,
60 },
61 [EC_HOST_EVENT_SMI_MASK] = {
62 EC_CMD_HOST_EVENT_SET_SMI_MASK, INVALID_HCMD,
63 EC_CMD_HOST_EVENT_GET_SMI_MASK,
64 },
65 [EC_HOST_EVENT_ALWAYS_REPORT_MASK] = {
66 INVALID_HCMD, INVALID_HCMD, INVALID_HCMD,
67 },
68 [EC_HOST_EVENT_ACTIVE_WAKE_MASK] = {
69 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
70 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
71 },
Patrick Georgia29d2342018-05-02 17:12:49 +020072 [EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX] = {
73 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
74 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
75 },
76 [EC_HOST_EVENT_LAZY_WAKE_MASK_S3] = {
77 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
78 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
79 },
80 [EC_HOST_EVENT_LAZY_WAKE_MASK_S5] = {
81 EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
82 EC_CMD_HOST_EVENT_GET_WAKE_MASK,
83 },
Jenny TC1dfc2c32017-12-14 14:24:39 +053084};
85
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080086void log_recovery_mode_switch(void)
87{
Furquan Shaikh8788fd62017-11-20 20:28:18 -080088 uint64_t *events;
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080089
90 if (cbmem_find(CBMEM_ID_EC_HOSTEVENT))
91 return;
92
93 events = cbmem_add(CBMEM_ID_EC_HOSTEVENT, sizeof(*events));
94 if (!events)
95 return;
96
97 *events = google_chromeec_get_events_b();
98}
99
100static void google_chromeec_elog_add_recovery_event(void *unused)
101{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800102 uint64_t *events = cbmem_find(CBMEM_ID_EC_HOSTEVENT);
Furquan Shaikhbce8bb62016-11-11 13:57:55 -0800103 uint8_t event_byte = EC_EVENT_KEYBOARD_RECOVERY;
104
105 if (!events)
106 return;
107
108 if (!(*events & EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY)))
109 return;
110
111 if (*events &
112 EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT))
113 event_byte = EC_EVENT_KEYBOARD_RECOVERY_HWREINIT;
114
115 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event_byte);
116}
117
118BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
119 google_chromeec_elog_add_recovery_event, NULL);
120
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800121uint8_t google_chromeec_calc_checksum(const uint8_t *data, int size)
122{
123 int csum;
124
125 for (csum = 0; size > 0; data++, size--)
126 csum += *data;
127 return (uint8_t)(csum & 0xff);
128}
129
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800130int google_chromeec_kbbacklight(int percent)
131{
132 struct chromeec_command cec_cmd;
133 struct ec_params_pwm_set_keyboard_backlight cmd_backlight;
134 struct ec_response_pwm_get_keyboard_backlight rsp_backlight;
135 /* if they were dumb, help them out */
136 percent = percent % 101;
137 cec_cmd.cmd_code = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
138 cec_cmd.cmd_version = 0;
139 cmd_backlight.percent = percent;
140 cec_cmd.cmd_data_in = &cmd_backlight;
141 cec_cmd.cmd_data_out = &rsp_backlight;
142 cec_cmd.cmd_size_in = sizeof(cmd_backlight);
143 cec_cmd.cmd_size_out = sizeof(rsp_backlight);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700144 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800145 google_chromeec_command(&cec_cmd);
146 printk(BIOS_DEBUG, "Google Chrome set keyboard backlight: %x status (%x)\n",
147 rsp_backlight.percent, cec_cmd.cmd_code);
148 return cec_cmd.cmd_code;
149
150}
151
152void google_chromeec_post(u8 postcode)
153{
154 /* backlight is a percent. postcode is a u8.
155 * Convert the u8 to %.
156 */
157 postcode = (postcode/4) + (postcode/8);
158 google_chromeec_kbbacklight(postcode);
159}
160
161/*
162 * Query the EC for specified mask indicating enabled events.
163 * The EC maintains separate event masks for SMI, SCI and WAKE.
164 */
Jenny TC1dfc2c32017-12-14 14:24:39 +0530165static int google_chromeec_uhepi_cmd(uint8_t mask, uint8_t action,
166 uint64_t *value)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800167{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530168 int ret;
169 struct ec_params_host_event req;
170 struct ec_response_host_event rsp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800171 struct chromeec_command cmd;
172
Jenny TC1dfc2c32017-12-14 14:24:39 +0530173 req.action = action;
174 req.mask_type = mask;
175 if (action != EC_HOST_EVENT_GET)
176 req.value = *value;
177 else
178 *value = 0;
179 cmd.cmd_code = EC_CMD_HOST_EVENT;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800180 cmd.cmd_version = 0;
181 cmd.cmd_data_in = &req;
182 cmd.cmd_size_in = sizeof(req);
183 cmd.cmd_data_out = &rsp;
184 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700185 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800186
Jenny TC1dfc2c32017-12-14 14:24:39 +0530187 ret = google_chromeec_command(&cmd);
188
189 if (action != EC_HOST_EVENT_GET)
190 return ret;
191 if (ret == 0)
192 *value = rsp.value;
193 return ret;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800194}
195
Jenny TC1dfc2c32017-12-14 14:24:39 +0530196static int google_chromeec_handle_non_uhepi_cmd(uint8_t hcmd, uint8_t action,
197 uint64_t *value)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700198{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530199 int ret = -1;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700200 struct ec_params_host_event_mask req;
201 struct ec_response_host_event_mask rsp;
202 struct chromeec_command cmd;
203
Jenny TC1dfc2c32017-12-14 14:24:39 +0530204 if (hcmd == INVALID_HCMD)
205 return ret;
206
207 if (action != EC_HOST_EVENT_GET)
208 req.mask = (uint32_t)*value;
209 else
210 *value = 0;
211
212 cmd.cmd_code = hcmd;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700213 cmd.cmd_version = 0;
214 cmd.cmd_data_in = &req;
215 cmd.cmd_size_in = sizeof(req);
216 cmd.cmd_data_out = &rsp;
217 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700218 cmd.cmd_dev_index = 0;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700219
Jenny TC1dfc2c32017-12-14 14:24:39 +0530220 ret = google_chromeec_command(&cmd);
221
222 if (action != EC_HOST_EVENT_GET)
223 return ret;
224 if (ret == 0)
225 *value = rsp.mask;
226
227 return ret;
228}
229
230bool google_chromeec_is_uhepi_supported(void)
231{
232#define UHEPI_SUPPORTED 1
233#define UHEPI_NOT_SUPPORTED 2
234
235 static int uhepi_support CAR_GLOBAL;
236
237 if (!uhepi_support) {
238 uhepi_support = google_chromeec_check_feature
Matt DeVillier41328932018-03-04 00:05:12 -0600239 (EC_FEATURE_UNIFIED_WAKE_MASKS) > 0 ? UHEPI_SUPPORTED :
Jenny TC1dfc2c32017-12-14 14:24:39 +0530240 UHEPI_NOT_SUPPORTED;
241 printk(BIOS_DEBUG, "Chrome EC: UHEPI %s\n",
242 uhepi_support == UHEPI_SUPPORTED ?
243 "supported" : "not supported");
244 }
245 return uhepi_support == UHEPI_SUPPORTED;
246}
247
248static uint64_t google_chromeec_get_mask(u8 type)
249{
250 u64 value = 0;
251
252 if (google_chromeec_is_uhepi_supported()) {
253 google_chromeec_uhepi_cmd(type, EC_HOST_EVENT_GET, &value);
254 } else {
255 assert(type < ARRAY_SIZE(event_map));
256 google_chromeec_handle_non_uhepi_cmd(
257 event_map[type].get_cmd,
258 EC_HOST_EVENT_GET, &value);
259 }
260 return value;
261}
262static int google_chromeec_clear_mask(u8 type, u64 mask)
263{
264 if (google_chromeec_is_uhepi_supported())
265 return google_chromeec_uhepi_cmd(type,
266 EC_HOST_EVENT_CLEAR, &mask);
267
268 assert(type < ARRAY_SIZE(event_map));
269 return google_chromeec_handle_non_uhepi_cmd(
270 event_map[type].clear_cmd,
271 EC_HOST_EVENT_CLEAR, &mask);
272}
273static int __unused google_chromeec_set_mask(u8 type, u64 mask)
274{
275 if (google_chromeec_is_uhepi_supported())
276 return google_chromeec_uhepi_cmd(type,
277 EC_HOST_EVENT_SET, &mask);
278
279 assert(type < ARRAY_SIZE(event_map));
280 return google_chromeec_handle_non_uhepi_cmd(
281 event_map[type].set_cmd,
282 EC_HOST_EVENT_SET, &mask);
283}
284
285static int google_chromeec_set_s3_lazy_wake_mask(uint64_t mask)
286{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800287 printk(BIOS_DEBUG, "Chrome EC: Set S3 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530288 mask);
289 return google_chromeec_set_mask
290 (EC_HOST_EVENT_LAZY_WAKE_MASK_S3, mask);
291}
292
293static int google_chromeec_set_s5_lazy_wake_mask(uint64_t mask)
294{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800295 printk(BIOS_DEBUG, "Chrome EC: Set S5 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530296 mask);
297 return google_chromeec_set_mask
298 (EC_HOST_EVENT_LAZY_WAKE_MASK_S5, mask);
299}
300
301static int google_chromeec_set_s0ix_lazy_wake_mask(uint64_t mask)
302{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800303 printk(BIOS_DEBUG, "Chrome EC: Set S0iX LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530304 mask);
305 return google_chromeec_set_mask
306 (EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, mask);
307}
308static void google_chromeec_set_lazy_wake_masks(uint64_t s5_mask,
309 uint64_t s3_mask, uint64_t s0ix_mask)
310{
311 if (google_chromeec_set_s5_lazy_wake_mask(s5_mask))
312 printk(BIOS_DEBUG, "Error: Set S5 LAZY WAKE mask failed\n");
313 if (google_chromeec_set_s3_lazy_wake_mask(s3_mask))
314 printk(BIOS_DEBUG, "Error: Set S3 LAZY WAKE mask failed\n");
315 if (google_chromeec_set_s0ix_lazy_wake_mask(s0ix_mask))
316 printk(BIOS_DEBUG, "Error: Set S0iX LAZY WAKE mask failed\n");
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700317}
318
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800319uint64_t google_chromeec_get_events_b(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800320{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530321 return google_chromeec_get_mask(EC_HOST_EVENT_B);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800322}
323
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800324int google_chromeec_clear_events_b(uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700325{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530326 printk(BIOS_DEBUG,
327 "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
328 return google_chromeec_clear_mask(EC_HOST_EVENT_B, mask);
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700329}
330
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700331int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
332{
333 struct chromeec_command cmd;
334
335 cmd.cmd_code = EC_CMD_GET_NEXT_EVENT;
336 cmd.cmd_version = 0;
337 cmd.cmd_data_in = NULL;
338 cmd.cmd_size_in = 0;
339 cmd.cmd_data_out = event;
340 cmd.cmd_size_out = sizeof(*event);
341 cmd.cmd_dev_index = 0;
342
343 return google_chromeec_command(&cmd);
344}
345
Duncan Laurie7378a172017-06-29 23:52:17 -0700346/* Get the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800347uint64_t google_chromeec_get_device_enabled_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700348{
349 struct ec_params_device_event req;
350 struct ec_response_device_event rsp;
351 struct chromeec_command cmd;
352
353 req.param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS;
354 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
355 cmd.cmd_version = 0;
356 cmd.cmd_data_in = &req;
357 cmd.cmd_size_in = sizeof(req);
358 cmd.cmd_data_out = &rsp;
359 cmd.cmd_size_out = sizeof(rsp);
360 cmd.cmd_dev_index = 0;
361
362 if (google_chromeec_command(&cmd) == 0)
363 return rsp.event_mask;
364 return 0;
365}
366
367/* Set the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800368int google_chromeec_set_device_enabled_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700369{
370 struct ec_params_device_event req;
371 struct ec_response_device_event rsp;
372 struct chromeec_command cmd;
373
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800374 req.event_mask = (uint32_t)mask;
Duncan Laurie7378a172017-06-29 23:52:17 -0700375 req.param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS;
376 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
377 cmd.cmd_version = 0;
378 cmd.cmd_data_in = &req;
379 cmd.cmd_size_in = sizeof(req);
380 cmd.cmd_data_out = &rsp;
381 cmd.cmd_size_out = sizeof(rsp);
382 cmd.cmd_dev_index = 0;
383
384 return google_chromeec_command(&cmd);
385}
386
387/* Read and clear pending device events */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800388uint64_t google_chromeec_get_device_current_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700389{
390 struct ec_params_device_event req;
391 struct ec_response_device_event rsp;
392 struct chromeec_command cmd;
393
394 req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
395 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
396 cmd.cmd_version = 0;
397 cmd.cmd_data_in = &req;
398 cmd.cmd_size_in = sizeof(req);
399 cmd.cmd_data_out = &rsp;
400 cmd.cmd_size_out = sizeof(rsp);
401 cmd.cmd_dev_index = 0;
402
403 if (google_chromeec_command(&cmd) == 0)
404 return rsp.event_mask;
405 return 0;
406}
407
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800408static void google_chromeec_log_device_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700409{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800410 uint64_t events;
Duncan Laurie7378a172017-06-29 23:52:17 -0700411 int i;
412
Furquan Shaikh2749c522017-10-04 14:01:41 -0700413 if (!IS_ENABLED(CONFIG_ELOG) || !mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700414 return;
415
416 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
417 return;
418
419 events = google_chromeec_get_device_current_events() & mask;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800420 printk(BIOS_INFO, "EC Device Events: 0x%016llx\n", events);
Duncan Laurie7378a172017-06-29 23:52:17 -0700421
422 for (i = 0; i < sizeof(events) * 8; i++) {
423 if (EC_DEVICE_EVENT_MASK(i) & events)
424 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
425 }
426}
427
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800428void google_chromeec_log_events(uint64_t mask)
Furquan Shaikh2749c522017-10-04 14:01:41 -0700429{
430 u8 event;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800431 uint64_t wake_mask;
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700432 bool restore_wake_mask = false;
Furquan Shaikh2749c522017-10-04 14:01:41 -0700433
434 if (!IS_ENABLED(CONFIG_ELOG))
435 return;
436
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700437 /*
438 * If the EC supports unified wake masks, then there is no need to set
439 * wake mask before reading out the host events.
440 */
441 if (google_chromeec_check_feature(EC_FEATURE_UNIFIED_WAKE_MASKS) != 1) {
442 wake_mask = google_chromeec_get_wake_mask();
443 google_chromeec_set_wake_mask(mask);
444 restore_wake_mask = true;
445 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700446
447 while ((event = google_chromeec_get_event()) != 0) {
448 if (EC_HOST_EVENT_MASK(event) & mask)
449 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event);
450 }
451
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700452 if (restore_wake_mask)
453 google_chromeec_set_wake_mask(wake_mask);
Furquan Shaikh2749c522017-10-04 14:01:41 -0700454}
455
456void google_chromeec_events_init(const struct google_chromeec_event_info *info,
457 bool is_s3_wakeup)
458{
459 if (is_s3_wakeup) {
460 google_chromeec_log_events(info->log_events |
461 info->s3_wake_events);
462
463 /* Log and clear device events that may wake the system. */
464 google_chromeec_log_device_events(info->s3_device_events);
465
466 /* Disable SMI and wake events. */
467 google_chromeec_set_smi_mask(0);
468
469 /* Clear pending events. */
470 while (google_chromeec_get_event() != 0)
471 ;
472
473 /* Restore SCI event mask. */
474 google_chromeec_set_sci_mask(info->sci_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530475
476 } else {
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700477 google_chromeec_set_smi_mask(info->smi_events);
478
Furquan Shaikh2749c522017-10-04 14:01:41 -0700479 google_chromeec_log_events(info->log_events |
480 info->s5_wake_events);
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700481
Jenny TC1dfc2c32017-12-14 14:24:39 +0530482 if (google_chromeec_is_uhepi_supported())
483 google_chromeec_set_lazy_wake_masks
484 (info->s5_wake_events,
485 info->s3_wake_events,
486 info->s0ix_wake_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530487 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700488
489 /* Clear wake event mask. */
490 google_chromeec_set_wake_mask(0);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530491
Furquan Shaikh2749c522017-10-04 14:01:41 -0700492}
493
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800494int google_chromeec_check_feature(int feature)
495{
496 struct chromeec_command cmd;
497 struct ec_response_get_features r;
498
499 cmd.cmd_code = EC_CMD_GET_FEATURES;
500 cmd.cmd_version = 0;
501 cmd.cmd_size_in = 0;
502 cmd.cmd_data_out = &r;
503 cmd.cmd_size_out = sizeof(r);
504 cmd.cmd_dev_index = 0;
505
506 if (google_chromeec_command(&cmd) != 0)
507 return -1;
508
509 if (feature >= 8 * sizeof(r.flags))
510 return -1;
511
512 return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
513}
514
Kevin Chiue2bb0592017-09-12 09:13:41 +0800515int google_chromeec_set_sku_id(u32 skuid)
516{
517 struct chromeec_command cmd;
518 struct ec_sku_id_info set_skuid = {
519 .sku_id = skuid
520 };
521
522 cmd.cmd_code = EC_CMD_SET_SKU_ID;
523 cmd.cmd_version = 0;
524 cmd.cmd_size_in = sizeof(set_skuid);
525 cmd.cmd_data_in = &set_skuid;
526 cmd.cmd_data_out = NULL;
527 cmd.cmd_size_out = 0;
528 cmd.cmd_dev_index = 0;
529
530 if (google_chromeec_command(&cmd) != 0)
531 return -1;
532
533 return 0;
534}
535
Simon Glass78659322016-06-10 20:58:24 -0600536#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_RTC)
537int rtc_get(struct rtc_time *time)
538{
539 struct chromeec_command cmd;
540 struct ec_response_rtc r;
541
542 cmd.cmd_code = EC_CMD_RTC_GET_VALUE;
543 cmd.cmd_version = 0;
544 cmd.cmd_size_in = 0;
545 cmd.cmd_data_out = &r;
546 cmd.cmd_size_out = sizeof(r);
547 cmd.cmd_dev_index = 0;
548
549 if (google_chromeec_command(&cmd) != 0)
550 return -1;
551
552 return rtc_to_tm(r.time, time);
553}
554#endif
555
Aaron Durbine68d22f2017-05-04 12:32:52 -0500556int google_chromeec_reboot(int dev_idx, enum ec_reboot_cmd type, uint8_t flags)
557{
558 struct ec_params_reboot_ec reboot_ec = {
559 .cmd = type,
560 .flags = flags,
561 };
562 struct ec_response_get_version cec_resp = { };
563 struct chromeec_command cec_cmd = {
564 .cmd_code = EC_CMD_REBOOT_EC,
565 .cmd_version = 0,
566 .cmd_data_in = &reboot_ec,
567 .cmd_data_out = &cec_resp,
568 .cmd_size_in = sizeof(reboot_ec),
569 .cmd_size_out = 0, /* ignore response, if any */
570 .cmd_dev_index = dev_idx,
571 };
572
573 return google_chromeec_command(&cec_cmd);
574}
575
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800576static int cbi_get_uint32(uint32_t *id, uint32_t type)
577{
578 struct chromeec_command cmd;
579 struct ec_params_get_cbi p;
Zhuohao Lee7824d9b2018-03-30 10:18:04 +0800580 uint32_t r = 0;
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800581 int rv;
582
583 p.type = type;
584
585 cmd.cmd_code = EC_CMD_GET_CROS_BOARD_INFO;
586 cmd.cmd_version = 0;
587 cmd.cmd_data_in = &p;
588 cmd.cmd_data_out = &r;
589 cmd.cmd_size_in = sizeof(p);
590 cmd.cmd_size_out = sizeof(r);
591 cmd.cmd_dev_index = 0;
592
593 rv = google_chromeec_command(&cmd);
594 if (rv < 0)
595 return rv;
596 *id = r;
597 return 0;
598}
599
600int google_chromeec_cbi_get_sku_id(uint32_t *id)
601{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800602 return cbi_get_uint32(id, CBI_TAG_SKU_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800603}
604
605int google_chromeec_cbi_get_oem_id(uint32_t *id)
606{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800607 return cbi_get_uint32(id, CBI_TAG_OEM_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800608}
609
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700610#ifndef __SMM__
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700611u16 google_chromeec_get_board_version(void)
612{
613 struct chromeec_command cmd;
614 struct ec_response_board_version board_v;
615
616 cmd.cmd_code = EC_CMD_GET_BOARD_VERSION;
617 cmd.cmd_version = 0;
618 cmd.cmd_size_in = 0;
619 cmd.cmd_size_out = sizeof(board_v);
620 cmd.cmd_data_out = &board_v;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700621 cmd.cmd_dev_index = 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700622
623 if (google_chromeec_command(&cmd) != 0)
624 return 0;
625
626 return board_v.board_version;
627}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700628
Patrick Georgi69206d92017-07-31 14:20:07 +0200629u32 google_chromeec_get_sku_id(void)
630{
631 struct chromeec_command cmd;
Kevin Chiue2bb0592017-09-12 09:13:41 +0800632 struct ec_sku_id_info sku_v;
Patrick Georgi69206d92017-07-31 14:20:07 +0200633
634 cmd.cmd_code = EC_CMD_GET_SKU_ID;
635 cmd.cmd_version = 0;
636 cmd.cmd_size_in = 0;
637 cmd.cmd_size_out = sizeof(sku_v);
638 cmd.cmd_data_out = &sku_v;
639 cmd.cmd_dev_index = 0;
640
641 if (google_chromeec_command(&cmd) != 0)
642 return 0;
643
644 return sku_v.sku_id;
645}
646
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700647int google_chromeec_vbnv_context(int is_read, uint8_t *data, int len)
648{
649 struct chromeec_command cec_cmd;
650 struct ec_params_vbnvcontext cmd_vbnvcontext;
651 struct ec_response_vbnvcontext rsp_vbnvcontext;
Julius Werner02e847b2015-02-20 13:36:11 -0800652 int retries = 3;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700653
654 if (len != EC_VBNV_BLOCK_SIZE)
655 return -1;
656
Patrick Georgif5060312015-10-13 22:14:22 +0200657retry:
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700658 cec_cmd.cmd_code = EC_CMD_VBNV_CONTEXT;
659 cec_cmd.cmd_version = EC_VER_VBNV_CONTEXT;
660 cec_cmd.cmd_data_in = &cmd_vbnvcontext;
661 cec_cmd.cmd_data_out = &rsp_vbnvcontext;
662 cec_cmd.cmd_size_in = sizeof(cmd_vbnvcontext);
Aaron Durbin3e497382014-08-06 14:28:52 -0500663 cec_cmd.cmd_size_out = is_read ? sizeof(rsp_vbnvcontext) : 0;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700664 cec_cmd.cmd_dev_index = 0;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700665
666 cmd_vbnvcontext.op = is_read ? EC_VBNV_CONTEXT_OP_READ :
667 EC_VBNV_CONTEXT_OP_WRITE;
668
669 if (!is_read)
670 memcpy(&cmd_vbnvcontext.block, data, EC_VBNV_BLOCK_SIZE);
671
Julius Werner02e847b2015-02-20 13:36:11 -0800672 if (google_chromeec_command(&cec_cmd)) {
673 printk(BIOS_ERR, "ERROR: failed to %s vbnv_ec context: %d\n",
674 is_read ? "read" : "write", (int)cec_cmd.cmd_code);
675 mdelay(10); /* just in case */
676 if (--retries)
677 goto retry;
678 }
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700679
680 if (is_read)
681 memcpy(data, &rsp_vbnvcontext.block, EC_VBNV_BLOCK_SIZE);
682
683 return cec_cmd.cmd_code;
684}
685
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700686#endif /* ! __SMM__ */
687
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800688#ifndef __PRE_RAM__
689
Gabe Black9f96aa62013-06-28 14:24:33 -0700690int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
691 uint8_t *buffer, int len, int is_read)
692{
693 union {
694 struct ec_params_i2c_passthru p;
695 uint8_t outbuf[EC_HOST_PARAM_SIZE];
696 } params;
697 union {
698 struct ec_response_i2c_passthru r;
699 uint8_t inbuf[EC_HOST_PARAM_SIZE];
700 } response;
701 struct ec_params_i2c_passthru *p = &params.p;
702 struct ec_response_i2c_passthru *r = &response.r;
703 struct ec_params_i2c_passthru_msg *msg = p->msg;
704 struct chromeec_command cmd;
705 uint8_t *pdata;
706 int read_len, write_len;
707 int size;
708 int rv;
709
710 p->port = 0;
711
712 if (alen != 1) {
713 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
714 return -1;
715 }
716 if (is_read) {
717 read_len = len;
718 write_len = alen;
719 p->num_msgs = 2;
720 } else {
721 read_len = 0;
722 write_len = alen + len;
723 p->num_msgs = 1;
724 }
725
726 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
727 if (size + write_len > sizeof(params)) {
728 printk(BIOS_ERR, "Params too large for buffer\n");
729 return -1;
730 }
731 if (sizeof(*r) + read_len > sizeof(response)) {
732 printk(BIOS_ERR, "Read length too big for buffer\n");
733 return -1;
734 }
735
736 /* Create a message to write the register address and optional data */
737 pdata = (uint8_t *)p + size;
738 msg->addr_flags = chip;
739 msg->len = write_len;
740 pdata[0] = addr;
741 if (!is_read)
742 memcpy(pdata + 1, buffer, len);
743 msg++;
744
745 if (read_len) {
746 msg->addr_flags = chip | EC_I2C_FLAG_READ;
747 msg->len = read_len;
748 }
749
750 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
751 cmd.cmd_version = 0;
752 cmd.cmd_data_in = p;
753 cmd.cmd_size_in = size + write_len;
754 cmd.cmd_data_out = r;
755 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700756 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -0700757 rv = google_chromeec_command(&cmd);
758 if (rv != 0)
759 return rv;
760
761 /* Parse response */
762 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
763 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
764 r->i2c_status);
765 return -1;
766 }
767
768 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
769 printk(BIOS_ERR, "Truncated read response\n");
770 return -1;
771 }
772
773 if (read_len)
774 memcpy(buffer, r->data, read_len);
775
776 return 0;
777}
778
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800779int google_chromeec_set_sci_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800780{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800781 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530782 return google_chromeec_set_mask(EC_HOST_EVENT_SCI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800783}
784
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800785int google_chromeec_set_smi_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800786{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800787 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530788 return google_chromeec_set_mask(EC_HOST_EVENT_SMI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800789}
790
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800791int google_chromeec_set_wake_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800792{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800793 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530794 return google_chromeec_set_mask
795 (EC_HOST_EVENT_ACTIVE_WAKE_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800796}
797
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800798uint64_t google_chromeec_get_wake_mask(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800799{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530800 return google_chromeec_get_mask(EC_HOST_EVENT_ACTIVE_WAKE_MASK);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800801}
802
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800803int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode)
804{
805 struct chromeec_command cmd;
806 struct ec_params_usb_charge_set_mode set_mode = {
807 .usb_port_id = port_id,
808 .mode = mode,
809 };
810
811 cmd.cmd_code = EC_CMD_USB_CHARGE_SET_MODE;
812 cmd.cmd_version = 0;
813 cmd.cmd_size_in = sizeof(set_mode);
814 cmd.cmd_data_in = &set_mode;
815 cmd.cmd_size_out = 0;
816 cmd.cmd_data_out = NULL;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700817 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800818
819 return google_chromeec_command(&cmd);
820}
821
Shelley Chenebd53302017-09-29 14:15:11 -0700822/* Get charger power info in Watts. Also returns type of charger */
823int google_chromeec_get_usb_pd_power_info(enum usb_chg_type *type,
824 u32 *max_watts)
825{
826 struct ec_params_usb_pd_power_info req = {
827 .port = PD_POWER_CHARGING_PORT,
828 };
829 struct ec_response_usb_pd_power_info rsp;
830 struct chromeec_command cmd = {
831 .cmd_code = EC_CMD_USB_PD_POWER_INFO,
832 .cmd_version = 0,
833 .cmd_data_in = &req,
834 .cmd_size_in = sizeof(req),
835 .cmd_data_out = &rsp,
836 .cmd_size_out = sizeof(rsp),
837 .cmd_dev_index = 0,
838 };
839 struct usb_chg_measures m;
840 int rv = google_chromeec_command(&cmd);
841 if (rv != 0)
842 return rv;
843 /* values are given in milliAmps and milliVolts */
844 *type = rsp.type;
845 m = rsp.meas;
846 *max_watts = (m.current_max * m.voltage_max) / 1000000;
847
848 return 0;
849}
850
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800851int google_chromeec_override_dedicated_charger_limit(u16 current_lim,
852 u16 voltage_lim)
853{
854 struct ec_params_dedicated_charger_limit p = {
855 .current_lim = current_lim,
856 .voltage_lim = voltage_lim,
857 };
858 struct chromeec_command cmd = {
859 .cmd_code = EC_CMD_OVERRIDE_DEDICATED_CHARGER_LIMIT,
860 .cmd_version = 0,
861 .cmd_data_in = &p,
862 .cmd_size_in = sizeof(p),
863 .cmd_data_out = NULL,
864 .cmd_size_out = 0,
865 .cmd_dev_index = 0,
866 };
867
868 return google_chromeec_command(&cmd);
869}
870
Julius Wernerea79d2b2016-11-21 20:14:07 -0800871int google_chromeec_set_usb_pd_role(u8 port, enum usb_pd_control_role role)
872{
873 struct ec_params_usb_pd_control req = {
874 .port = port,
875 .role = role,
876 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
877 .swap = USB_PD_CTRL_SWAP_NONE,
878 };
879 struct ec_response_usb_pd_control rsp;
880 struct chromeec_command cmd = {
881 .cmd_code = EC_CMD_USB_PD_CONTROL,
882 .cmd_version = 0,
883 .cmd_data_in = &req,
884 .cmd_size_in = sizeof(req),
885 .cmd_data_out = &rsp,
886 .cmd_size_out = sizeof(rsp),
887 .cmd_dev_index = 0,
888 };
889
890 return google_chromeec_command(&cmd);
891}
892
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800893#ifndef __SMM__
894
895static
896int google_chromeec_hello(void)
897{
898 struct chromeec_command cec_cmd;
899 struct ec_params_hello cmd_hello;
900 struct ec_response_hello rsp_hello;
901 cmd_hello.in_data = 0x10203040;
902 cec_cmd.cmd_code = EC_CMD_HELLO;
903 cec_cmd.cmd_version = 0;
904 cec_cmd.cmd_data_in = &cmd_hello.in_data;
905 cec_cmd.cmd_data_out = &rsp_hello.out_data;
906 cec_cmd.cmd_size_in = sizeof(cmd_hello.in_data);
907 cec_cmd.cmd_size_out = sizeof(rsp_hello.out_data);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700908 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800909 google_chromeec_command(&cec_cmd);
910 printk(BIOS_DEBUG, "Google Chrome EC: Hello got back %x status (%x)\n",
911 rsp_hello.out_data, cec_cmd.cmd_code);
912 return cec_cmd.cmd_code;
913}
914
915static int ec_image_type; /* Cached EC image type (ro or rw). */
916
Hung-Te Lin76720d02013-04-15 18:06:32 +0800917void google_chromeec_init(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800918{
919 struct chromeec_command cec_cmd;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800920 struct ec_response_get_version cec_resp = {{0}};
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800921
922 printk(BIOS_DEBUG, "Google Chrome EC: Initializing keyboard.\n");
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800923
924 google_chromeec_hello();
925
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800926 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
927 cec_cmd.cmd_version = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800928 cec_cmd.cmd_data_out = &cec_resp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800929 cec_cmd.cmd_size_in = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800930 cec_cmd.cmd_size_out = sizeof(cec_resp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700931 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800932 google_chromeec_command(&cec_cmd);
933
934 if (cec_cmd.cmd_code) {
935 printk(BIOS_DEBUG,
936 "Google Chrome EC: version command failed!\n");
937 } else {
938 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Hung-Te Lin76720d02013-04-15 18:06:32 +0800939 printk(BIOS_DEBUG, " ro: %s\n", cec_resp.version_string_ro);
940 printk(BIOS_DEBUG, " rw: %s\n", cec_resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800941 printk(BIOS_DEBUG, " running image: %d\n",
Hung-Te Lin76720d02013-04-15 18:06:32 +0800942 cec_resp.current_image);
943 ec_image_type = cec_resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800944 }
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800945}
946
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800947int google_ec_running_ro(void)
948{
949 return (ec_image_type == EC_IMAGE_RO);
950}
951#endif /* ! __SMM__ */
952
953#endif /* ! __PRE_RAM__ */
Daisuke Nojiri476c2c52018-01-26 17:36:44 -0800954
955/**
956 * Check if EC/TCPM is in an alternate mode or not.
957 *
958 * @param svid SVID of the alternate mode to check
959 * @return 0: Not in the mode. -1: Error. 1: Yes.
960 */
961int google_chromeec_pd_get_amode(uint16_t svid)
962{
963 struct ec_response_usb_pd_ports r;
964 struct chromeec_command cmd;
965 int i;
966
967 cmd.cmd_code = EC_CMD_USB_PD_PORTS;
968 cmd.cmd_version = 0;
969 cmd.cmd_data_in = NULL;
970 cmd.cmd_size_in = 0;
971 cmd.cmd_data_out = &r;
972 cmd.cmd_size_out = sizeof(r);
973 cmd.cmd_dev_index = 0;
974 if (google_chromeec_command(&cmd) < 0)
975 return -1;
976
977 for (i = 0; i < r.num_ports; i++) {
978 struct ec_params_usb_pd_get_mode_request p;
979 struct ec_params_usb_pd_get_mode_response res;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -0700980 int svid_idx = 0;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -0800981
982 do {
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -0700983 /* Reset cmd in each iteration in case
984 google_chromeec_command changes it. */
985 p.port = i;
986 p.svid_idx = svid_idx;
987 cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE;
988 cmd.cmd_version = 0;
989 cmd.cmd_data_in = &p;
990 cmd.cmd_size_in = sizeof(p);
991 cmd.cmd_data_out = &res;
992 cmd.cmd_size_out = sizeof(res);
993 cmd.cmd_dev_index = 0;
994
Daisuke Nojiri476c2c52018-01-26 17:36:44 -0800995 if (google_chromeec_command(&cmd) < 0)
996 return -1;
997 if (res.svid == svid)
998 return 1;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -0700999 svid_idx++;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001000 } while (res.svid);
1001 }
1002
1003 return 0;
1004}
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001005
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001006
1007#define USB_SID_DISPLAYPORT 0xff01
1008
Daisuke Nojirid182b632018-02-16 17:50:06 -08001009/**
1010 * Wait for DisplayPort to be ready
1011 *
1012 * @param timeout Wait aborts after <timeout> ms.
1013 * @return 1: Success or 0: Timeout.
1014 */
1015int google_chromeec_wait_for_displayport(long timeout)
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001016{
1017 struct stopwatch sw;
1018
Daisuke Nojirid182b632018-02-16 17:50:06 -08001019 printk(BIOS_INFO, "Waiting for DisplayPort\n");
1020 stopwatch_init_msecs_expire(&sw, timeout);
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001021 while (google_chromeec_pd_get_amode(USB_SID_DISPLAYPORT) != 1) {
1022 if (stopwatch_expired(&sw)) {
1023 printk(BIOS_WARNING,
Daisuke Nojirid182b632018-02-16 17:50:06 -08001024 "DisplayPort not ready after %ldms. Abort.\n",
1025 timeout);
1026 return 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001027 }
1028 mdelay(200);
1029 }
Daisuke Nojirid182b632018-02-16 17:50:06 -08001030 printk(BIOS_INFO, "DisplayPort ready after %lu ms\n",
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001031 stopwatch_duration_msecs(&sw));
Daisuke Nojirid182b632018-02-16 17:50:06 -08001032
1033 return 1;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001034}