blob: fb3ffab1811b3e67ff954434a5f547c495c157a6 [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 },
72};
73
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080074void log_recovery_mode_switch(void)
75{
Furquan Shaikh8788fd62017-11-20 20:28:18 -080076 uint64_t *events;
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080077
78 if (cbmem_find(CBMEM_ID_EC_HOSTEVENT))
79 return;
80
81 events = cbmem_add(CBMEM_ID_EC_HOSTEVENT, sizeof(*events));
82 if (!events)
83 return;
84
85 *events = google_chromeec_get_events_b();
86}
87
88static void google_chromeec_elog_add_recovery_event(void *unused)
89{
Furquan Shaikh8788fd62017-11-20 20:28:18 -080090 uint64_t *events = cbmem_find(CBMEM_ID_EC_HOSTEVENT);
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080091 uint8_t event_byte = EC_EVENT_KEYBOARD_RECOVERY;
92
93 if (!events)
94 return;
95
96 if (!(*events & EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY)))
97 return;
98
99 if (*events &
100 EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT))
101 event_byte = EC_EVENT_KEYBOARD_RECOVERY_HWREINIT;
102
103 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event_byte);
104}
105
106BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
107 google_chromeec_elog_add_recovery_event, NULL);
108
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800109uint8_t google_chromeec_calc_checksum(const uint8_t *data, int size)
110{
111 int csum;
112
113 for (csum = 0; size > 0; data++, size--)
114 csum += *data;
115 return (uint8_t)(csum & 0xff);
116}
117
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800118int google_chromeec_kbbacklight(int percent)
119{
120 struct chromeec_command cec_cmd;
121 struct ec_params_pwm_set_keyboard_backlight cmd_backlight;
122 struct ec_response_pwm_get_keyboard_backlight rsp_backlight;
123 /* if they were dumb, help them out */
124 percent = percent % 101;
125 cec_cmd.cmd_code = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
126 cec_cmd.cmd_version = 0;
127 cmd_backlight.percent = percent;
128 cec_cmd.cmd_data_in = &cmd_backlight;
129 cec_cmd.cmd_data_out = &rsp_backlight;
130 cec_cmd.cmd_size_in = sizeof(cmd_backlight);
131 cec_cmd.cmd_size_out = sizeof(rsp_backlight);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700132 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800133 google_chromeec_command(&cec_cmd);
134 printk(BIOS_DEBUG, "Google Chrome set keyboard backlight: %x status (%x)\n",
135 rsp_backlight.percent, cec_cmd.cmd_code);
136 return cec_cmd.cmd_code;
137
138}
139
140void google_chromeec_post(u8 postcode)
141{
142 /* backlight is a percent. postcode is a u8.
143 * Convert the u8 to %.
144 */
145 postcode = (postcode/4) + (postcode/8);
146 google_chromeec_kbbacklight(postcode);
147}
148
149/*
150 * Query the EC for specified mask indicating enabled events.
151 * The EC maintains separate event masks for SMI, SCI and WAKE.
152 */
Jenny TC1dfc2c32017-12-14 14:24:39 +0530153static int google_chromeec_uhepi_cmd(uint8_t mask, uint8_t action,
154 uint64_t *value)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800155{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530156 int ret;
157 struct ec_params_host_event req;
158 struct ec_response_host_event rsp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800159 struct chromeec_command cmd;
160
Jenny TC1dfc2c32017-12-14 14:24:39 +0530161 req.action = action;
162 req.mask_type = mask;
163 if (action != EC_HOST_EVENT_GET)
164 req.value = *value;
165 else
166 *value = 0;
167 cmd.cmd_code = EC_CMD_HOST_EVENT;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800168 cmd.cmd_version = 0;
169 cmd.cmd_data_in = &req;
170 cmd.cmd_size_in = sizeof(req);
171 cmd.cmd_data_out = &rsp;
172 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700173 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800174
Jenny TC1dfc2c32017-12-14 14:24:39 +0530175 ret = google_chromeec_command(&cmd);
176
177 if (action != EC_HOST_EVENT_GET)
178 return ret;
179 if (ret == 0)
180 *value = rsp.value;
181 return ret;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800182}
183
Jenny TC1dfc2c32017-12-14 14:24:39 +0530184static int google_chromeec_handle_non_uhepi_cmd(uint8_t hcmd, uint8_t action,
185 uint64_t *value)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700186{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530187 int ret = -1;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700188 struct ec_params_host_event_mask req;
189 struct ec_response_host_event_mask rsp;
190 struct chromeec_command cmd;
191
Jenny TC1dfc2c32017-12-14 14:24:39 +0530192 if (hcmd == INVALID_HCMD)
193 return ret;
194
195 if (action != EC_HOST_EVENT_GET)
196 req.mask = (uint32_t)*value;
197 else
198 *value = 0;
199
200 cmd.cmd_code = hcmd;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700201 cmd.cmd_version = 0;
202 cmd.cmd_data_in = &req;
203 cmd.cmd_size_in = sizeof(req);
204 cmd.cmd_data_out = &rsp;
205 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700206 cmd.cmd_dev_index = 0;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700207
Jenny TC1dfc2c32017-12-14 14:24:39 +0530208 ret = google_chromeec_command(&cmd);
209
210 if (action != EC_HOST_EVENT_GET)
211 return ret;
212 if (ret == 0)
213 *value = rsp.mask;
214
215 return ret;
216}
217
218bool google_chromeec_is_uhepi_supported(void)
219{
220#define UHEPI_SUPPORTED 1
221#define UHEPI_NOT_SUPPORTED 2
222
223 static int uhepi_support CAR_GLOBAL;
224
225 if (!uhepi_support) {
226 uhepi_support = google_chromeec_check_feature
Matt DeVillier41328932018-03-04 00:05:12 -0600227 (EC_FEATURE_UNIFIED_WAKE_MASKS) > 0 ? UHEPI_SUPPORTED :
Jenny TC1dfc2c32017-12-14 14:24:39 +0530228 UHEPI_NOT_SUPPORTED;
229 printk(BIOS_DEBUG, "Chrome EC: UHEPI %s\n",
230 uhepi_support == UHEPI_SUPPORTED ?
231 "supported" : "not supported");
232 }
233 return uhepi_support == UHEPI_SUPPORTED;
234}
235
236static uint64_t google_chromeec_get_mask(u8 type)
237{
238 u64 value = 0;
239
240 if (google_chromeec_is_uhepi_supported()) {
241 google_chromeec_uhepi_cmd(type, EC_HOST_EVENT_GET, &value);
242 } else {
243 assert(type < ARRAY_SIZE(event_map));
244 google_chromeec_handle_non_uhepi_cmd(
245 event_map[type].get_cmd,
246 EC_HOST_EVENT_GET, &value);
247 }
248 return value;
249}
250static int google_chromeec_clear_mask(u8 type, u64 mask)
251{
252 if (google_chromeec_is_uhepi_supported())
253 return google_chromeec_uhepi_cmd(type,
254 EC_HOST_EVENT_CLEAR, &mask);
255
256 assert(type < ARRAY_SIZE(event_map));
257 return google_chromeec_handle_non_uhepi_cmd(
258 event_map[type].clear_cmd,
259 EC_HOST_EVENT_CLEAR, &mask);
260}
261static int __unused google_chromeec_set_mask(u8 type, u64 mask)
262{
263 if (google_chromeec_is_uhepi_supported())
264 return google_chromeec_uhepi_cmd(type,
265 EC_HOST_EVENT_SET, &mask);
266
267 assert(type < ARRAY_SIZE(event_map));
268 return google_chromeec_handle_non_uhepi_cmd(
269 event_map[type].set_cmd,
270 EC_HOST_EVENT_SET, &mask);
271}
272
273static int google_chromeec_set_s3_lazy_wake_mask(uint64_t mask)
274{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800275 printk(BIOS_DEBUG, "Chrome EC: Set S3 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530276 mask);
277 return google_chromeec_set_mask
278 (EC_HOST_EVENT_LAZY_WAKE_MASK_S3, mask);
279}
280
281static int google_chromeec_set_s5_lazy_wake_mask(uint64_t mask)
282{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800283 printk(BIOS_DEBUG, "Chrome EC: Set S5 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530284 mask);
285 return google_chromeec_set_mask
286 (EC_HOST_EVENT_LAZY_WAKE_MASK_S5, mask);
287}
288
289static int google_chromeec_set_s0ix_lazy_wake_mask(uint64_t mask)
290{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800291 printk(BIOS_DEBUG, "Chrome EC: Set S0iX LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530292 mask);
293 return google_chromeec_set_mask
294 (EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, mask);
295}
296static void google_chromeec_set_lazy_wake_masks(uint64_t s5_mask,
297 uint64_t s3_mask, uint64_t s0ix_mask)
298{
299 if (google_chromeec_set_s5_lazy_wake_mask(s5_mask))
300 printk(BIOS_DEBUG, "Error: Set S5 LAZY WAKE mask failed\n");
301 if (google_chromeec_set_s3_lazy_wake_mask(s3_mask))
302 printk(BIOS_DEBUG, "Error: Set S3 LAZY WAKE mask failed\n");
303 if (google_chromeec_set_s0ix_lazy_wake_mask(s0ix_mask))
304 printk(BIOS_DEBUG, "Error: Set S0iX LAZY WAKE mask failed\n");
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700305}
306
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800307uint64_t google_chromeec_get_events_b(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800308{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530309 return google_chromeec_get_mask(EC_HOST_EVENT_B);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800310}
311
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800312int google_chromeec_clear_events_b(uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700313{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530314 printk(BIOS_DEBUG,
315 "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
316 return google_chromeec_clear_mask(EC_HOST_EVENT_B, mask);
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700317}
318
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700319int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
320{
321 struct chromeec_command cmd;
322
323 cmd.cmd_code = EC_CMD_GET_NEXT_EVENT;
324 cmd.cmd_version = 0;
325 cmd.cmd_data_in = NULL;
326 cmd.cmd_size_in = 0;
327 cmd.cmd_data_out = event;
328 cmd.cmd_size_out = sizeof(*event);
329 cmd.cmd_dev_index = 0;
330
331 return google_chromeec_command(&cmd);
332}
333
Duncan Laurie7378a172017-06-29 23:52:17 -0700334/* Get the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800335uint64_t google_chromeec_get_device_enabled_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700336{
337 struct ec_params_device_event req;
338 struct ec_response_device_event rsp;
339 struct chromeec_command cmd;
340
341 req.param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS;
342 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
343 cmd.cmd_version = 0;
344 cmd.cmd_data_in = &req;
345 cmd.cmd_size_in = sizeof(req);
346 cmd.cmd_data_out = &rsp;
347 cmd.cmd_size_out = sizeof(rsp);
348 cmd.cmd_dev_index = 0;
349
350 if (google_chromeec_command(&cmd) == 0)
351 return rsp.event_mask;
352 return 0;
353}
354
355/* Set the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800356int google_chromeec_set_device_enabled_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700357{
358 struct ec_params_device_event req;
359 struct ec_response_device_event rsp;
360 struct chromeec_command cmd;
361
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800362 req.event_mask = (uint32_t)mask;
Duncan Laurie7378a172017-06-29 23:52:17 -0700363 req.param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS;
364 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
365 cmd.cmd_version = 0;
366 cmd.cmd_data_in = &req;
367 cmd.cmd_size_in = sizeof(req);
368 cmd.cmd_data_out = &rsp;
369 cmd.cmd_size_out = sizeof(rsp);
370 cmd.cmd_dev_index = 0;
371
372 return google_chromeec_command(&cmd);
373}
374
375/* Read and clear pending device events */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800376uint64_t google_chromeec_get_device_current_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700377{
378 struct ec_params_device_event req;
379 struct ec_response_device_event rsp;
380 struct chromeec_command cmd;
381
382 req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
383 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
384 cmd.cmd_version = 0;
385 cmd.cmd_data_in = &req;
386 cmd.cmd_size_in = sizeof(req);
387 cmd.cmd_data_out = &rsp;
388 cmd.cmd_size_out = sizeof(rsp);
389 cmd.cmd_dev_index = 0;
390
391 if (google_chromeec_command(&cmd) == 0)
392 return rsp.event_mask;
393 return 0;
394}
395
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800396static void google_chromeec_log_device_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700397{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800398 uint64_t events;
Duncan Laurie7378a172017-06-29 23:52:17 -0700399 int i;
400
Furquan Shaikh2749c522017-10-04 14:01:41 -0700401 if (!IS_ENABLED(CONFIG_ELOG) || !mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700402 return;
403
404 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
405 return;
406
407 events = google_chromeec_get_device_current_events() & mask;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800408 printk(BIOS_INFO, "EC Device Events: 0x%016llx\n", events);
Duncan Laurie7378a172017-06-29 23:52:17 -0700409
410 for (i = 0; i < sizeof(events) * 8; i++) {
411 if (EC_DEVICE_EVENT_MASK(i) & events)
412 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
413 }
414}
415
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800416void google_chromeec_log_events(uint64_t mask)
Furquan Shaikh2749c522017-10-04 14:01:41 -0700417{
418 u8 event;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800419 uint64_t wake_mask;
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700420 bool restore_wake_mask = false;
Furquan Shaikh2749c522017-10-04 14:01:41 -0700421
422 if (!IS_ENABLED(CONFIG_ELOG))
423 return;
424
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700425 /*
426 * If the EC supports unified wake masks, then there is no need to set
427 * wake mask before reading out the host events.
428 */
429 if (google_chromeec_check_feature(EC_FEATURE_UNIFIED_WAKE_MASKS) != 1) {
430 wake_mask = google_chromeec_get_wake_mask();
431 google_chromeec_set_wake_mask(mask);
432 restore_wake_mask = true;
433 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700434
435 while ((event = google_chromeec_get_event()) != 0) {
436 if (EC_HOST_EVENT_MASK(event) & mask)
437 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event);
438 }
439
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700440 if (restore_wake_mask)
441 google_chromeec_set_wake_mask(wake_mask);
Furquan Shaikh2749c522017-10-04 14:01:41 -0700442}
443
444void google_chromeec_events_init(const struct google_chromeec_event_info *info,
445 bool is_s3_wakeup)
446{
447 if (is_s3_wakeup) {
448 google_chromeec_log_events(info->log_events |
449 info->s3_wake_events);
450
451 /* Log and clear device events that may wake the system. */
452 google_chromeec_log_device_events(info->s3_device_events);
453
454 /* Disable SMI and wake events. */
455 google_chromeec_set_smi_mask(0);
456
457 /* Clear pending events. */
458 while (google_chromeec_get_event() != 0)
459 ;
460
461 /* Restore SCI event mask. */
462 google_chromeec_set_sci_mask(info->sci_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530463
464 } else {
Furquan Shaikh2749c522017-10-04 14:01:41 -0700465 google_chromeec_log_events(info->log_events |
466 info->s5_wake_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530467 if (google_chromeec_is_uhepi_supported())
468 google_chromeec_set_lazy_wake_masks
469 (info->s5_wake_events,
470 info->s3_wake_events,
471 info->s0ix_wake_events);
472
473 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700474
475 /* Clear wake event mask. */
476 google_chromeec_set_wake_mask(0);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530477
Furquan Shaikh2749c522017-10-04 14:01:41 -0700478}
479
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800480int google_chromeec_check_feature(int feature)
481{
482 struct chromeec_command cmd;
483 struct ec_response_get_features r;
484
485 cmd.cmd_code = EC_CMD_GET_FEATURES;
486 cmd.cmd_version = 0;
487 cmd.cmd_size_in = 0;
488 cmd.cmd_data_out = &r;
489 cmd.cmd_size_out = sizeof(r);
490 cmd.cmd_dev_index = 0;
491
492 if (google_chromeec_command(&cmd) != 0)
493 return -1;
494
495 if (feature >= 8 * sizeof(r.flags))
496 return -1;
497
498 return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
499}
500
Kevin Chiue2bb0592017-09-12 09:13:41 +0800501int google_chromeec_set_sku_id(u32 skuid)
502{
503 struct chromeec_command cmd;
504 struct ec_sku_id_info set_skuid = {
505 .sku_id = skuid
506 };
507
508 cmd.cmd_code = EC_CMD_SET_SKU_ID;
509 cmd.cmd_version = 0;
510 cmd.cmd_size_in = sizeof(set_skuid);
511 cmd.cmd_data_in = &set_skuid;
512 cmd.cmd_data_out = NULL;
513 cmd.cmd_size_out = 0;
514 cmd.cmd_dev_index = 0;
515
516 if (google_chromeec_command(&cmd) != 0)
517 return -1;
518
519 return 0;
520}
521
Simon Glass78659322016-06-10 20:58:24 -0600522#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_RTC)
523int rtc_get(struct rtc_time *time)
524{
525 struct chromeec_command cmd;
526 struct ec_response_rtc r;
527
528 cmd.cmd_code = EC_CMD_RTC_GET_VALUE;
529 cmd.cmd_version = 0;
530 cmd.cmd_size_in = 0;
531 cmd.cmd_data_out = &r;
532 cmd.cmd_size_out = sizeof(r);
533 cmd.cmd_dev_index = 0;
534
535 if (google_chromeec_command(&cmd) != 0)
536 return -1;
537
538 return rtc_to_tm(r.time, time);
539}
540#endif
541
Aaron Durbine68d22f2017-05-04 12:32:52 -0500542int google_chromeec_reboot(int dev_idx, enum ec_reboot_cmd type, uint8_t flags)
543{
544 struct ec_params_reboot_ec reboot_ec = {
545 .cmd = type,
546 .flags = flags,
547 };
548 struct ec_response_get_version cec_resp = { };
549 struct chromeec_command cec_cmd = {
550 .cmd_code = EC_CMD_REBOOT_EC,
551 .cmd_version = 0,
552 .cmd_data_in = &reboot_ec,
553 .cmd_data_out = &cec_resp,
554 .cmd_size_in = sizeof(reboot_ec),
555 .cmd_size_out = 0, /* ignore response, if any */
556 .cmd_dev_index = dev_idx,
557 };
558
559 return google_chromeec_command(&cec_cmd);
560}
561
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800562static int cbi_get_uint32(uint32_t *id, uint32_t type)
563{
564 struct chromeec_command cmd;
565 struct ec_params_get_cbi p;
Zhuohao Lee7824d9b2018-03-30 10:18:04 +0800566 uint32_t r = 0;
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800567 int rv;
568
569 p.type = type;
570
571 cmd.cmd_code = EC_CMD_GET_CROS_BOARD_INFO;
572 cmd.cmd_version = 0;
573 cmd.cmd_data_in = &p;
574 cmd.cmd_data_out = &r;
575 cmd.cmd_size_in = sizeof(p);
576 cmd.cmd_size_out = sizeof(r);
577 cmd.cmd_dev_index = 0;
578
579 rv = google_chromeec_command(&cmd);
580 if (rv < 0)
581 return rv;
582 *id = r;
583 return 0;
584}
585
586int google_chromeec_cbi_get_sku_id(uint32_t *id)
587{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800588 return cbi_get_uint32(id, CBI_TAG_SKU_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800589}
590
591int google_chromeec_cbi_get_oem_id(uint32_t *id)
592{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800593 return cbi_get_uint32(id, CBI_TAG_OEM_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800594}
595
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700596#ifndef __SMM__
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700597u16 google_chromeec_get_board_version(void)
598{
599 struct chromeec_command cmd;
600 struct ec_response_board_version board_v;
601
602 cmd.cmd_code = EC_CMD_GET_BOARD_VERSION;
603 cmd.cmd_version = 0;
604 cmd.cmd_size_in = 0;
605 cmd.cmd_size_out = sizeof(board_v);
606 cmd.cmd_data_out = &board_v;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700607 cmd.cmd_dev_index = 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700608
609 if (google_chromeec_command(&cmd) != 0)
610 return 0;
611
612 return board_v.board_version;
613}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700614
Patrick Georgi69206d92017-07-31 14:20:07 +0200615u32 google_chromeec_get_sku_id(void)
616{
617 struct chromeec_command cmd;
Kevin Chiue2bb0592017-09-12 09:13:41 +0800618 struct ec_sku_id_info sku_v;
Patrick Georgi69206d92017-07-31 14:20:07 +0200619
620 cmd.cmd_code = EC_CMD_GET_SKU_ID;
621 cmd.cmd_version = 0;
622 cmd.cmd_size_in = 0;
623 cmd.cmd_size_out = sizeof(sku_v);
624 cmd.cmd_data_out = &sku_v;
625 cmd.cmd_dev_index = 0;
626
627 if (google_chromeec_command(&cmd) != 0)
628 return 0;
629
630 return sku_v.sku_id;
631}
632
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700633int google_chromeec_vbnv_context(int is_read, uint8_t *data, int len)
634{
635 struct chromeec_command cec_cmd;
636 struct ec_params_vbnvcontext cmd_vbnvcontext;
637 struct ec_response_vbnvcontext rsp_vbnvcontext;
Julius Werner02e847b2015-02-20 13:36:11 -0800638 int retries = 3;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700639
640 if (len != EC_VBNV_BLOCK_SIZE)
641 return -1;
642
Patrick Georgif5060312015-10-13 22:14:22 +0200643retry:
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700644 cec_cmd.cmd_code = EC_CMD_VBNV_CONTEXT;
645 cec_cmd.cmd_version = EC_VER_VBNV_CONTEXT;
646 cec_cmd.cmd_data_in = &cmd_vbnvcontext;
647 cec_cmd.cmd_data_out = &rsp_vbnvcontext;
648 cec_cmd.cmd_size_in = sizeof(cmd_vbnvcontext);
Aaron Durbin3e497382014-08-06 14:28:52 -0500649 cec_cmd.cmd_size_out = is_read ? sizeof(rsp_vbnvcontext) : 0;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700650 cec_cmd.cmd_dev_index = 0;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700651
652 cmd_vbnvcontext.op = is_read ? EC_VBNV_CONTEXT_OP_READ :
653 EC_VBNV_CONTEXT_OP_WRITE;
654
655 if (!is_read)
656 memcpy(&cmd_vbnvcontext.block, data, EC_VBNV_BLOCK_SIZE);
657
Julius Werner02e847b2015-02-20 13:36:11 -0800658 if (google_chromeec_command(&cec_cmd)) {
659 printk(BIOS_ERR, "ERROR: failed to %s vbnv_ec context: %d\n",
660 is_read ? "read" : "write", (int)cec_cmd.cmd_code);
661 mdelay(10); /* just in case */
662 if (--retries)
663 goto retry;
664 }
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700665
666 if (is_read)
667 memcpy(data, &rsp_vbnvcontext.block, EC_VBNV_BLOCK_SIZE);
668
669 return cec_cmd.cmd_code;
670}
671
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700672#endif /* ! __SMM__ */
673
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800674#ifndef __PRE_RAM__
675
Gabe Black9f96aa62013-06-28 14:24:33 -0700676int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
677 uint8_t *buffer, int len, int is_read)
678{
679 union {
680 struct ec_params_i2c_passthru p;
681 uint8_t outbuf[EC_HOST_PARAM_SIZE];
682 } params;
683 union {
684 struct ec_response_i2c_passthru r;
685 uint8_t inbuf[EC_HOST_PARAM_SIZE];
686 } response;
687 struct ec_params_i2c_passthru *p = &params.p;
688 struct ec_response_i2c_passthru *r = &response.r;
689 struct ec_params_i2c_passthru_msg *msg = p->msg;
690 struct chromeec_command cmd;
691 uint8_t *pdata;
692 int read_len, write_len;
693 int size;
694 int rv;
695
696 p->port = 0;
697
698 if (alen != 1) {
699 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
700 return -1;
701 }
702 if (is_read) {
703 read_len = len;
704 write_len = alen;
705 p->num_msgs = 2;
706 } else {
707 read_len = 0;
708 write_len = alen + len;
709 p->num_msgs = 1;
710 }
711
712 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
713 if (size + write_len > sizeof(params)) {
714 printk(BIOS_ERR, "Params too large for buffer\n");
715 return -1;
716 }
717 if (sizeof(*r) + read_len > sizeof(response)) {
718 printk(BIOS_ERR, "Read length too big for buffer\n");
719 return -1;
720 }
721
722 /* Create a message to write the register address and optional data */
723 pdata = (uint8_t *)p + size;
724 msg->addr_flags = chip;
725 msg->len = write_len;
726 pdata[0] = addr;
727 if (!is_read)
728 memcpy(pdata + 1, buffer, len);
729 msg++;
730
731 if (read_len) {
732 msg->addr_flags = chip | EC_I2C_FLAG_READ;
733 msg->len = read_len;
734 }
735
736 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
737 cmd.cmd_version = 0;
738 cmd.cmd_data_in = p;
739 cmd.cmd_size_in = size + write_len;
740 cmd.cmd_data_out = r;
741 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700742 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -0700743 rv = google_chromeec_command(&cmd);
744 if (rv != 0)
745 return rv;
746
747 /* Parse response */
748 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
749 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
750 r->i2c_status);
751 return -1;
752 }
753
754 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
755 printk(BIOS_ERR, "Truncated read response\n");
756 return -1;
757 }
758
759 if (read_len)
760 memcpy(buffer, r->data, read_len);
761
762 return 0;
763}
764
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800765int google_chromeec_set_sci_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800766{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800767 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530768 return google_chromeec_set_mask(EC_HOST_EVENT_SCI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800769}
770
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800771int google_chromeec_set_smi_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800772{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800773 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530774 return google_chromeec_set_mask(EC_HOST_EVENT_SMI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800775}
776
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800777int google_chromeec_set_wake_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800778{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800779 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530780 return google_chromeec_set_mask
781 (EC_HOST_EVENT_ACTIVE_WAKE_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800782}
783
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800784uint64_t google_chromeec_get_wake_mask(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800785{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530786 return google_chromeec_get_mask(EC_HOST_EVENT_ACTIVE_WAKE_MASK);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800787}
788
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800789int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode)
790{
791 struct chromeec_command cmd;
792 struct ec_params_usb_charge_set_mode set_mode = {
793 .usb_port_id = port_id,
794 .mode = mode,
795 };
796
797 cmd.cmd_code = EC_CMD_USB_CHARGE_SET_MODE;
798 cmd.cmd_version = 0;
799 cmd.cmd_size_in = sizeof(set_mode);
800 cmd.cmd_data_in = &set_mode;
801 cmd.cmd_size_out = 0;
802 cmd.cmd_data_out = NULL;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700803 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800804
805 return google_chromeec_command(&cmd);
806}
807
Shelley Chenebd53302017-09-29 14:15:11 -0700808/* Get charger power info in Watts. Also returns type of charger */
809int google_chromeec_get_usb_pd_power_info(enum usb_chg_type *type,
810 u32 *max_watts)
811{
812 struct ec_params_usb_pd_power_info req = {
813 .port = PD_POWER_CHARGING_PORT,
814 };
815 struct ec_response_usb_pd_power_info rsp;
816 struct chromeec_command cmd = {
817 .cmd_code = EC_CMD_USB_PD_POWER_INFO,
818 .cmd_version = 0,
819 .cmd_data_in = &req,
820 .cmd_size_in = sizeof(req),
821 .cmd_data_out = &rsp,
822 .cmd_size_out = sizeof(rsp),
823 .cmd_dev_index = 0,
824 };
825 struct usb_chg_measures m;
826 int rv = google_chromeec_command(&cmd);
827 if (rv != 0)
828 return rv;
829 /* values are given in milliAmps and milliVolts */
830 *type = rsp.type;
831 m = rsp.meas;
832 *max_watts = (m.current_max * m.voltage_max) / 1000000;
833
834 return 0;
835}
836
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800837int google_chromeec_override_dedicated_charger_limit(u16 current_lim,
838 u16 voltage_lim)
839{
840 struct ec_params_dedicated_charger_limit p = {
841 .current_lim = current_lim,
842 .voltage_lim = voltage_lim,
843 };
844 struct chromeec_command cmd = {
845 .cmd_code = EC_CMD_OVERRIDE_DEDICATED_CHARGER_LIMIT,
846 .cmd_version = 0,
847 .cmd_data_in = &p,
848 .cmd_size_in = sizeof(p),
849 .cmd_data_out = NULL,
850 .cmd_size_out = 0,
851 .cmd_dev_index = 0,
852 };
853
854 return google_chromeec_command(&cmd);
855}
856
Julius Wernerea79d2b2016-11-21 20:14:07 -0800857int google_chromeec_set_usb_pd_role(u8 port, enum usb_pd_control_role role)
858{
859 struct ec_params_usb_pd_control req = {
860 .port = port,
861 .role = role,
862 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
863 .swap = USB_PD_CTRL_SWAP_NONE,
864 };
865 struct ec_response_usb_pd_control rsp;
866 struct chromeec_command cmd = {
867 .cmd_code = EC_CMD_USB_PD_CONTROL,
868 .cmd_version = 0,
869 .cmd_data_in = &req,
870 .cmd_size_in = sizeof(req),
871 .cmd_data_out = &rsp,
872 .cmd_size_out = sizeof(rsp),
873 .cmd_dev_index = 0,
874 };
875
876 return google_chromeec_command(&cmd);
877}
878
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800879#ifndef __SMM__
880
881static
882int google_chromeec_hello(void)
883{
884 struct chromeec_command cec_cmd;
885 struct ec_params_hello cmd_hello;
886 struct ec_response_hello rsp_hello;
887 cmd_hello.in_data = 0x10203040;
888 cec_cmd.cmd_code = EC_CMD_HELLO;
889 cec_cmd.cmd_version = 0;
890 cec_cmd.cmd_data_in = &cmd_hello.in_data;
891 cec_cmd.cmd_data_out = &rsp_hello.out_data;
892 cec_cmd.cmd_size_in = sizeof(cmd_hello.in_data);
893 cec_cmd.cmd_size_out = sizeof(rsp_hello.out_data);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700894 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800895 google_chromeec_command(&cec_cmd);
896 printk(BIOS_DEBUG, "Google Chrome EC: Hello got back %x status (%x)\n",
897 rsp_hello.out_data, cec_cmd.cmd_code);
898 return cec_cmd.cmd_code;
899}
900
901static int ec_image_type; /* Cached EC image type (ro or rw). */
902
Hung-Te Lin76720d02013-04-15 18:06:32 +0800903void google_chromeec_init(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800904{
905 struct chromeec_command cec_cmd;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800906 struct ec_response_get_version cec_resp = {{0}};
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800907
908 printk(BIOS_DEBUG, "Google Chrome EC: Initializing keyboard.\n");
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800909
910 google_chromeec_hello();
911
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800912 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
913 cec_cmd.cmd_version = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800914 cec_cmd.cmd_data_out = &cec_resp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800915 cec_cmd.cmd_size_in = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800916 cec_cmd.cmd_size_out = sizeof(cec_resp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700917 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800918 google_chromeec_command(&cec_cmd);
919
920 if (cec_cmd.cmd_code) {
921 printk(BIOS_DEBUG,
922 "Google Chrome EC: version command failed!\n");
923 } else {
924 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Hung-Te Lin76720d02013-04-15 18:06:32 +0800925 printk(BIOS_DEBUG, " ro: %s\n", cec_resp.version_string_ro);
926 printk(BIOS_DEBUG, " rw: %s\n", cec_resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800927 printk(BIOS_DEBUG, " running image: %d\n",
Hung-Te Lin76720d02013-04-15 18:06:32 +0800928 cec_resp.current_image);
929 ec_image_type = cec_resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800930 }
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800931}
932
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800933int google_ec_running_ro(void)
934{
935 return (ec_image_type == EC_IMAGE_RO);
936}
937#endif /* ! __SMM__ */
938
939#endif /* ! __PRE_RAM__ */
Daisuke Nojiri476c2c52018-01-26 17:36:44 -0800940
941/**
942 * Check if EC/TCPM is in an alternate mode or not.
943 *
944 * @param svid SVID of the alternate mode to check
945 * @return 0: Not in the mode. -1: Error. 1: Yes.
946 */
947int google_chromeec_pd_get_amode(uint16_t svid)
948{
949 struct ec_response_usb_pd_ports r;
950 struct chromeec_command cmd;
951 int i;
952
953 cmd.cmd_code = EC_CMD_USB_PD_PORTS;
954 cmd.cmd_version = 0;
955 cmd.cmd_data_in = NULL;
956 cmd.cmd_size_in = 0;
957 cmd.cmd_data_out = &r;
958 cmd.cmd_size_out = sizeof(r);
959 cmd.cmd_dev_index = 0;
960 if (google_chromeec_command(&cmd) < 0)
961 return -1;
962
963 for (i = 0; i < r.num_ports; i++) {
964 struct ec_params_usb_pd_get_mode_request p;
965 struct ec_params_usb_pd_get_mode_response res;
966
967 p.port = i;
968 p.svid_idx = 0;
969 cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE;
970 cmd.cmd_version = 0;
971 cmd.cmd_data_in = &p;
972 cmd.cmd_size_in = sizeof(p);
973 cmd.cmd_data_out = &res;
974 cmd.cmd_size_out = sizeof(res);
975 cmd.cmd_dev_index = 0;
976
977 do {
978 if (google_chromeec_command(&cmd) < 0)
979 return -1;
980 if (res.svid == svid)
981 return 1;
982 p.svid_idx++;
983 } while (res.svid);
984 }
985
986 return 0;
987}
Daisuke Nojiriebb86be2018-01-26 17:36:44 -0800988
Daisuke Nojiriebb86be2018-01-26 17:36:44 -0800989
990#define USB_SID_DISPLAYPORT 0xff01
991
Daisuke Nojirid182b632018-02-16 17:50:06 -0800992/**
993 * Wait for DisplayPort to be ready
994 *
995 * @param timeout Wait aborts after <timeout> ms.
996 * @return 1: Success or 0: Timeout.
997 */
998int google_chromeec_wait_for_displayport(long timeout)
Daisuke Nojiriebb86be2018-01-26 17:36:44 -0800999{
1000 struct stopwatch sw;
1001
Daisuke Nojirid182b632018-02-16 17:50:06 -08001002 printk(BIOS_INFO, "Waiting for DisplayPort\n");
1003 stopwatch_init_msecs_expire(&sw, timeout);
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001004 while (google_chromeec_pd_get_amode(USB_SID_DISPLAYPORT) != 1) {
1005 if (stopwatch_expired(&sw)) {
1006 printk(BIOS_WARNING,
Daisuke Nojirid182b632018-02-16 17:50:06 -08001007 "DisplayPort not ready after %ldms. Abort.\n",
1008 timeout);
1009 return 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001010 }
1011 mdelay(200);
1012 }
Daisuke Nojirid182b632018-02-16 17:50:06 -08001013 printk(BIOS_INFO, "DisplayPort ready after %lu ms\n",
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001014 stopwatch_duration_msecs(&sw));
Daisuke Nojirid182b632018-02-16 17:50:06 -08001015
1016 return 1;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001017}