blob: b44fffe9bc31d01641fb82dea37437d32d301341 [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>
20#include <arch/io.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080021#include <bootmode.h>
22#include <bootstate.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -080023#include <delay.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080024#include <elog.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010025#include <halt.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>
Edward O'Callaghanb57fef92014-06-17 20:13:08 +100030
Stefan Reinauerd6682e82013-02-21 15:39:35 -080031#include "chip.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080032#include "ec.h"
33#include "ec_commands.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080034
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080035void log_recovery_mode_switch(void)
36{
Furquan Shaikh8788fd62017-11-20 20:28:18 -080037 uint64_t *events;
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080038
39 if (cbmem_find(CBMEM_ID_EC_HOSTEVENT))
40 return;
41
42 events = cbmem_add(CBMEM_ID_EC_HOSTEVENT, sizeof(*events));
43 if (!events)
44 return;
45
46 *events = google_chromeec_get_events_b();
47}
48
49static void google_chromeec_elog_add_recovery_event(void *unused)
50{
Furquan Shaikh8788fd62017-11-20 20:28:18 -080051 uint64_t *events = cbmem_find(CBMEM_ID_EC_HOSTEVENT);
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080052 uint8_t event_byte = EC_EVENT_KEYBOARD_RECOVERY;
53
54 if (!events)
55 return;
56
57 if (!(*events & EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY)))
58 return;
59
60 if (*events &
61 EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT))
62 event_byte = EC_EVENT_KEYBOARD_RECOVERY_HWREINIT;
63
64 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event_byte);
65}
66
67BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
68 google_chromeec_elog_add_recovery_event, NULL);
69
Hung-Te Lin6bfbb332013-04-15 18:27:24 +080070uint8_t google_chromeec_calc_checksum(const uint8_t *data, int size)
71{
72 int csum;
73
74 for (csum = 0; size > 0; data++, size--)
75 csum += *data;
76 return (uint8_t)(csum & 0xff);
77}
78
Stefan Reinauerd6682e82013-02-21 15:39:35 -080079int google_chromeec_kbbacklight(int percent)
80{
81 struct chromeec_command cec_cmd;
82 struct ec_params_pwm_set_keyboard_backlight cmd_backlight;
83 struct ec_response_pwm_get_keyboard_backlight rsp_backlight;
84 /* if they were dumb, help them out */
85 percent = percent % 101;
86 cec_cmd.cmd_code = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
87 cec_cmd.cmd_version = 0;
88 cmd_backlight.percent = percent;
89 cec_cmd.cmd_data_in = &cmd_backlight;
90 cec_cmd.cmd_data_out = &rsp_backlight;
91 cec_cmd.cmd_size_in = sizeof(cmd_backlight);
92 cec_cmd.cmd_size_out = sizeof(rsp_backlight);
Duncan Lauriefc0f5172014-09-18 12:54:02 -070093 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -080094 google_chromeec_command(&cec_cmd);
95 printk(BIOS_DEBUG, "Google Chrome set keyboard backlight: %x status (%x)\n",
96 rsp_backlight.percent, cec_cmd.cmd_code);
97 return cec_cmd.cmd_code;
98
99}
100
101void google_chromeec_post(u8 postcode)
102{
103 /* backlight is a percent. postcode is a u8.
104 * Convert the u8 to %.
105 */
106 postcode = (postcode/4) + (postcode/8);
107 google_chromeec_kbbacklight(postcode);
108}
109
110/*
111 * Query the EC for specified mask indicating enabled events.
112 * The EC maintains separate event masks for SMI, SCI and WAKE.
113 */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800114static uint64_t google_chromeec_get_mask(u8 type)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800115{
116 struct ec_params_host_event_mask req;
117 struct ec_response_host_event_mask rsp;
118 struct chromeec_command cmd;
119
120 cmd.cmd_code = type;
121 cmd.cmd_version = 0;
122 cmd.cmd_data_in = &req;
123 cmd.cmd_size_in = sizeof(req);
124 cmd.cmd_data_out = &rsp;
125 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700126 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800127
128 if (google_chromeec_command(&cmd) == 0)
129 return rsp.mask;
130 return 0;
131}
132
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800133static int google_chromeec_set_mask(uint8_t type, uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700134{
135 struct ec_params_host_event_mask req;
136 struct ec_response_host_event_mask rsp;
137 struct chromeec_command cmd;
138
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800139 req.mask = (uint32_t)mask;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700140 cmd.cmd_code = type;
141 cmd.cmd_version = 0;
142 cmd.cmd_data_in = &req;
143 cmd.cmd_size_in = sizeof(req);
144 cmd.cmd_data_out = &rsp;
145 cmd.cmd_size_out = sizeof(rsp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700146 cmd.cmd_dev_index = 0;
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700147
148 return google_chromeec_command(&cmd);
149}
150
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800151uint64_t google_chromeec_get_events_b(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800152{
153 return google_chromeec_get_mask(EC_CMD_HOST_EVENT_GET_B);
154}
155
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800156int google_chromeec_clear_events_b(uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700157{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800158 printk(BIOS_DEBUG, "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700159 return google_chromeec_set_mask(
160 EC_CMD_HOST_EVENT_CLEAR_B, mask);
161}
162
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700163int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
164{
165 struct chromeec_command cmd;
166
167 cmd.cmd_code = EC_CMD_GET_NEXT_EVENT;
168 cmd.cmd_version = 0;
169 cmd.cmd_data_in = NULL;
170 cmd.cmd_size_in = 0;
171 cmd.cmd_data_out = event;
172 cmd.cmd_size_out = sizeof(*event);
173 cmd.cmd_dev_index = 0;
174
175 return google_chromeec_command(&cmd);
176}
177
Duncan Laurie7378a172017-06-29 23:52:17 -0700178/* Get the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800179uint64_t google_chromeec_get_device_enabled_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700180{
181 struct ec_params_device_event req;
182 struct ec_response_device_event rsp;
183 struct chromeec_command cmd;
184
185 req.param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS;
186 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
187 cmd.cmd_version = 0;
188 cmd.cmd_data_in = &req;
189 cmd.cmd_size_in = sizeof(req);
190 cmd.cmd_data_out = &rsp;
191 cmd.cmd_size_out = sizeof(rsp);
192 cmd.cmd_dev_index = 0;
193
194 if (google_chromeec_command(&cmd) == 0)
195 return rsp.event_mask;
196 return 0;
197}
198
199/* Set the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800200int google_chromeec_set_device_enabled_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700201{
202 struct ec_params_device_event req;
203 struct ec_response_device_event rsp;
204 struct chromeec_command cmd;
205
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800206 req.event_mask = (uint32_t)mask;
Duncan Laurie7378a172017-06-29 23:52:17 -0700207 req.param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS;
208 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
209 cmd.cmd_version = 0;
210 cmd.cmd_data_in = &req;
211 cmd.cmd_size_in = sizeof(req);
212 cmd.cmd_data_out = &rsp;
213 cmd.cmd_size_out = sizeof(rsp);
214 cmd.cmd_dev_index = 0;
215
216 return google_chromeec_command(&cmd);
217}
218
219/* Read and clear pending device events */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800220uint64_t google_chromeec_get_device_current_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700221{
222 struct ec_params_device_event req;
223 struct ec_response_device_event rsp;
224 struct chromeec_command cmd;
225
226 req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
227 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
228 cmd.cmd_version = 0;
229 cmd.cmd_data_in = &req;
230 cmd.cmd_size_in = sizeof(req);
231 cmd.cmd_data_out = &rsp;
232 cmd.cmd_size_out = sizeof(rsp);
233 cmd.cmd_dev_index = 0;
234
235 if (google_chromeec_command(&cmd) == 0)
236 return rsp.event_mask;
237 return 0;
238}
239
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800240static void google_chromeec_log_device_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700241{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800242 uint64_t events;
Duncan Laurie7378a172017-06-29 23:52:17 -0700243 int i;
244
Furquan Shaikh2749c522017-10-04 14:01:41 -0700245 if (!IS_ENABLED(CONFIG_ELOG) || !mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700246 return;
247
248 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
249 return;
250
251 events = google_chromeec_get_device_current_events() & mask;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800252 printk(BIOS_INFO, "EC Device Events: 0x%016llx\n", events);
Duncan Laurie7378a172017-06-29 23:52:17 -0700253
254 for (i = 0; i < sizeof(events) * 8; i++) {
255 if (EC_DEVICE_EVENT_MASK(i) & events)
256 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
257 }
258}
259
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800260void google_chromeec_log_events(uint64_t mask)
Furquan Shaikh2749c522017-10-04 14:01:41 -0700261{
262 u8 event;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800263 uint64_t wake_mask;
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700264 bool restore_wake_mask = false;
Furquan Shaikh2749c522017-10-04 14:01:41 -0700265
266 if (!IS_ENABLED(CONFIG_ELOG))
267 return;
268
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700269 /*
270 * If the EC supports unified wake masks, then there is no need to set
271 * wake mask before reading out the host events.
272 */
273 if (google_chromeec_check_feature(EC_FEATURE_UNIFIED_WAKE_MASKS) != 1) {
274 wake_mask = google_chromeec_get_wake_mask();
275 google_chromeec_set_wake_mask(mask);
276 restore_wake_mask = true;
277 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700278
279 while ((event = google_chromeec_get_event()) != 0) {
280 if (EC_HOST_EVENT_MASK(event) & mask)
281 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event);
282 }
283
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700284 if (restore_wake_mask)
285 google_chromeec_set_wake_mask(wake_mask);
Furquan Shaikh2749c522017-10-04 14:01:41 -0700286}
287
288void google_chromeec_events_init(const struct google_chromeec_event_info *info,
289 bool is_s3_wakeup)
290{
291 if (is_s3_wakeup) {
292 google_chromeec_log_events(info->log_events |
293 info->s3_wake_events);
294
295 /* Log and clear device events that may wake the system. */
296 google_chromeec_log_device_events(info->s3_device_events);
297
298 /* Disable SMI and wake events. */
299 google_chromeec_set_smi_mask(0);
300
301 /* Clear pending events. */
302 while (google_chromeec_get_event() != 0)
303 ;
304
305 /* Restore SCI event mask. */
306 google_chromeec_set_sci_mask(info->sci_events);
307 } else
308 google_chromeec_log_events(info->log_events |
309 info->s5_wake_events);
310
311 /* Clear wake event mask. */
312 google_chromeec_set_wake_mask(0);
313}
314
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800315int google_chromeec_check_feature(int feature)
316{
317 struct chromeec_command cmd;
318 struct ec_response_get_features r;
319
320 cmd.cmd_code = EC_CMD_GET_FEATURES;
321 cmd.cmd_version = 0;
322 cmd.cmd_size_in = 0;
323 cmd.cmd_data_out = &r;
324 cmd.cmd_size_out = sizeof(r);
325 cmd.cmd_dev_index = 0;
326
327 if (google_chromeec_command(&cmd) != 0)
328 return -1;
329
330 if (feature >= 8 * sizeof(r.flags))
331 return -1;
332
333 return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
334}
335
Kevin Chiue2bb0592017-09-12 09:13:41 +0800336int google_chromeec_set_sku_id(u32 skuid)
337{
338 struct chromeec_command cmd;
339 struct ec_sku_id_info set_skuid = {
340 .sku_id = skuid
341 };
342
343 cmd.cmd_code = EC_CMD_SET_SKU_ID;
344 cmd.cmd_version = 0;
345 cmd.cmd_size_in = sizeof(set_skuid);
346 cmd.cmd_data_in = &set_skuid;
347 cmd.cmd_data_out = NULL;
348 cmd.cmd_size_out = 0;
349 cmd.cmd_dev_index = 0;
350
351 if (google_chromeec_command(&cmd) != 0)
352 return -1;
353
354 return 0;
355}
356
Simon Glass78659322016-06-10 20:58:24 -0600357#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_RTC)
358int rtc_get(struct rtc_time *time)
359{
360 struct chromeec_command cmd;
361 struct ec_response_rtc r;
362
363 cmd.cmd_code = EC_CMD_RTC_GET_VALUE;
364 cmd.cmd_version = 0;
365 cmd.cmd_size_in = 0;
366 cmd.cmd_data_out = &r;
367 cmd.cmd_size_out = sizeof(r);
368 cmd.cmd_dev_index = 0;
369
370 if (google_chromeec_command(&cmd) != 0)
371 return -1;
372
373 return rtc_to_tm(r.time, time);
374}
375#endif
376
Aaron Durbine68d22f2017-05-04 12:32:52 -0500377int google_chromeec_reboot(int dev_idx, enum ec_reboot_cmd type, uint8_t flags)
378{
379 struct ec_params_reboot_ec reboot_ec = {
380 .cmd = type,
381 .flags = flags,
382 };
383 struct ec_response_get_version cec_resp = { };
384 struct chromeec_command cec_cmd = {
385 .cmd_code = EC_CMD_REBOOT_EC,
386 .cmd_version = 0,
387 .cmd_data_in = &reboot_ec,
388 .cmd_data_out = &cec_resp,
389 .cmd_size_in = sizeof(reboot_ec),
390 .cmd_size_out = 0, /* ignore response, if any */
391 .cmd_dev_index = dev_idx,
392 };
393
394 return google_chromeec_command(&cec_cmd);
395}
396
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700397#ifndef __SMM__
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700398u16 google_chromeec_get_board_version(void)
399{
400 struct chromeec_command cmd;
401 struct ec_response_board_version board_v;
402
403 cmd.cmd_code = EC_CMD_GET_BOARD_VERSION;
404 cmd.cmd_version = 0;
405 cmd.cmd_size_in = 0;
406 cmd.cmd_size_out = sizeof(board_v);
407 cmd.cmd_data_out = &board_v;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700408 cmd.cmd_dev_index = 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700409
410 if (google_chromeec_command(&cmd) != 0)
411 return 0;
412
413 return board_v.board_version;
414}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700415
Patrick Georgi69206d92017-07-31 14:20:07 +0200416u32 google_chromeec_get_sku_id(void)
417{
418 struct chromeec_command cmd;
Kevin Chiue2bb0592017-09-12 09:13:41 +0800419 struct ec_sku_id_info sku_v;
Patrick Georgi69206d92017-07-31 14:20:07 +0200420
421 cmd.cmd_code = EC_CMD_GET_SKU_ID;
422 cmd.cmd_version = 0;
423 cmd.cmd_size_in = 0;
424 cmd.cmd_size_out = sizeof(sku_v);
425 cmd.cmd_data_out = &sku_v;
426 cmd.cmd_dev_index = 0;
427
428 if (google_chromeec_command(&cmd) != 0)
429 return 0;
430
431 return sku_v.sku_id;
432}
433
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700434int google_chromeec_vbnv_context(int is_read, uint8_t *data, int len)
435{
436 struct chromeec_command cec_cmd;
437 struct ec_params_vbnvcontext cmd_vbnvcontext;
438 struct ec_response_vbnvcontext rsp_vbnvcontext;
Julius Werner02e847b2015-02-20 13:36:11 -0800439 int retries = 3;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700440
441 if (len != EC_VBNV_BLOCK_SIZE)
442 return -1;
443
Patrick Georgif5060312015-10-13 22:14:22 +0200444retry:
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700445 cec_cmd.cmd_code = EC_CMD_VBNV_CONTEXT;
446 cec_cmd.cmd_version = EC_VER_VBNV_CONTEXT;
447 cec_cmd.cmd_data_in = &cmd_vbnvcontext;
448 cec_cmd.cmd_data_out = &rsp_vbnvcontext;
449 cec_cmd.cmd_size_in = sizeof(cmd_vbnvcontext);
Aaron Durbin3e497382014-08-06 14:28:52 -0500450 cec_cmd.cmd_size_out = is_read ? sizeof(rsp_vbnvcontext) : 0;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700451 cec_cmd.cmd_dev_index = 0;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700452
453 cmd_vbnvcontext.op = is_read ? EC_VBNV_CONTEXT_OP_READ :
454 EC_VBNV_CONTEXT_OP_WRITE;
455
456 if (!is_read)
457 memcpy(&cmd_vbnvcontext.block, data, EC_VBNV_BLOCK_SIZE);
458
Julius Werner02e847b2015-02-20 13:36:11 -0800459 if (google_chromeec_command(&cec_cmd)) {
460 printk(BIOS_ERR, "ERROR: failed to %s vbnv_ec context: %d\n",
461 is_read ? "read" : "write", (int)cec_cmd.cmd_code);
462 mdelay(10); /* just in case */
463 if (--retries)
464 goto retry;
465 }
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700466
467 if (is_read)
468 memcpy(data, &rsp_vbnvcontext.block, EC_VBNV_BLOCK_SIZE);
469
470 return cec_cmd.cmd_code;
471}
472
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700473#endif /* ! __SMM__ */
474
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800475#ifndef __PRE_RAM__
476
Gabe Black9f96aa62013-06-28 14:24:33 -0700477int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
478 uint8_t *buffer, int len, int is_read)
479{
480 union {
481 struct ec_params_i2c_passthru p;
482 uint8_t outbuf[EC_HOST_PARAM_SIZE];
483 } params;
484 union {
485 struct ec_response_i2c_passthru r;
486 uint8_t inbuf[EC_HOST_PARAM_SIZE];
487 } response;
488 struct ec_params_i2c_passthru *p = &params.p;
489 struct ec_response_i2c_passthru *r = &response.r;
490 struct ec_params_i2c_passthru_msg *msg = p->msg;
491 struct chromeec_command cmd;
492 uint8_t *pdata;
493 int read_len, write_len;
494 int size;
495 int rv;
496
497 p->port = 0;
498
499 if (alen != 1) {
500 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
501 return -1;
502 }
503 if (is_read) {
504 read_len = len;
505 write_len = alen;
506 p->num_msgs = 2;
507 } else {
508 read_len = 0;
509 write_len = alen + len;
510 p->num_msgs = 1;
511 }
512
513 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
514 if (size + write_len > sizeof(params)) {
515 printk(BIOS_ERR, "Params too large for buffer\n");
516 return -1;
517 }
518 if (sizeof(*r) + read_len > sizeof(response)) {
519 printk(BIOS_ERR, "Read length too big for buffer\n");
520 return -1;
521 }
522
523 /* Create a message to write the register address and optional data */
524 pdata = (uint8_t *)p + size;
525 msg->addr_flags = chip;
526 msg->len = write_len;
527 pdata[0] = addr;
528 if (!is_read)
529 memcpy(pdata + 1, buffer, len);
530 msg++;
531
532 if (read_len) {
533 msg->addr_flags = chip | EC_I2C_FLAG_READ;
534 msg->len = read_len;
535 }
536
537 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
538 cmd.cmd_version = 0;
539 cmd.cmd_data_in = p;
540 cmd.cmd_size_in = size + write_len;
541 cmd.cmd_data_out = r;
542 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700543 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -0700544 rv = google_chromeec_command(&cmd);
545 if (rv != 0)
546 return rv;
547
548 /* Parse response */
549 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
550 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
551 r->i2c_status);
552 return -1;
553 }
554
555 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
556 printk(BIOS_ERR, "Truncated read response\n");
557 return -1;
558 }
559
560 if (read_len)
561 memcpy(buffer, r->data, read_len);
562
563 return 0;
564}
565
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800566int google_chromeec_set_sci_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800567{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800568 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800569 return google_chromeec_set_mask(
570 EC_CMD_HOST_EVENT_SET_SCI_MASK, mask);
571}
572
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800573int google_chromeec_set_smi_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800574{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800575 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800576 return google_chromeec_set_mask(
577 EC_CMD_HOST_EVENT_SET_SMI_MASK, mask);
578}
579
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800580int google_chromeec_set_wake_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800581{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800582 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800583 return google_chromeec_set_mask(
584 EC_CMD_HOST_EVENT_SET_WAKE_MASK, mask);
585}
586
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800587uint64_t google_chromeec_get_wake_mask(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800588{
589 return google_chromeec_get_mask(
590 EC_CMD_HOST_EVENT_GET_WAKE_MASK);
591}
592
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800593int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode)
594{
595 struct chromeec_command cmd;
596 struct ec_params_usb_charge_set_mode set_mode = {
597 .usb_port_id = port_id,
598 .mode = mode,
599 };
600
601 cmd.cmd_code = EC_CMD_USB_CHARGE_SET_MODE;
602 cmd.cmd_version = 0;
603 cmd.cmd_size_in = sizeof(set_mode);
604 cmd.cmd_data_in = &set_mode;
605 cmd.cmd_size_out = 0;
606 cmd.cmd_data_out = NULL;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700607 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800608
609 return google_chromeec_command(&cmd);
610}
611
Shelley Chenebd53302017-09-29 14:15:11 -0700612/* Get charger power info in Watts. Also returns type of charger */
613int google_chromeec_get_usb_pd_power_info(enum usb_chg_type *type,
614 u32 *max_watts)
615{
616 struct ec_params_usb_pd_power_info req = {
617 .port = PD_POWER_CHARGING_PORT,
618 };
619 struct ec_response_usb_pd_power_info rsp;
620 struct chromeec_command cmd = {
621 .cmd_code = EC_CMD_USB_PD_POWER_INFO,
622 .cmd_version = 0,
623 .cmd_data_in = &req,
624 .cmd_size_in = sizeof(req),
625 .cmd_data_out = &rsp,
626 .cmd_size_out = sizeof(rsp),
627 .cmd_dev_index = 0,
628 };
629 struct usb_chg_measures m;
630 int rv = google_chromeec_command(&cmd);
631 if (rv != 0)
632 return rv;
633 /* values are given in milliAmps and milliVolts */
634 *type = rsp.type;
635 m = rsp.meas;
636 *max_watts = (m.current_max * m.voltage_max) / 1000000;
637
638 return 0;
639}
640
Julius Wernerea79d2b2016-11-21 20:14:07 -0800641int google_chromeec_set_usb_pd_role(u8 port, enum usb_pd_control_role role)
642{
643 struct ec_params_usb_pd_control req = {
644 .port = port,
645 .role = role,
646 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
647 .swap = USB_PD_CTRL_SWAP_NONE,
648 };
649 struct ec_response_usb_pd_control rsp;
650 struct chromeec_command cmd = {
651 .cmd_code = EC_CMD_USB_PD_CONTROL,
652 .cmd_version = 0,
653 .cmd_data_in = &req,
654 .cmd_size_in = sizeof(req),
655 .cmd_data_out = &rsp,
656 .cmd_size_out = sizeof(rsp),
657 .cmd_dev_index = 0,
658 };
659
660 return google_chromeec_command(&cmd);
661}
662
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800663#ifndef __SMM__
664
665static
666int google_chromeec_hello(void)
667{
668 struct chromeec_command cec_cmd;
669 struct ec_params_hello cmd_hello;
670 struct ec_response_hello rsp_hello;
671 cmd_hello.in_data = 0x10203040;
672 cec_cmd.cmd_code = EC_CMD_HELLO;
673 cec_cmd.cmd_version = 0;
674 cec_cmd.cmd_data_in = &cmd_hello.in_data;
675 cec_cmd.cmd_data_out = &rsp_hello.out_data;
676 cec_cmd.cmd_size_in = sizeof(cmd_hello.in_data);
677 cec_cmd.cmd_size_out = sizeof(rsp_hello.out_data);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700678 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800679 google_chromeec_command(&cec_cmd);
680 printk(BIOS_DEBUG, "Google Chrome EC: Hello got back %x status (%x)\n",
681 rsp_hello.out_data, cec_cmd.cmd_code);
682 return cec_cmd.cmd_code;
683}
684
685static int ec_image_type; /* Cached EC image type (ro or rw). */
686
Hung-Te Lin76720d02013-04-15 18:06:32 +0800687void google_chromeec_init(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800688{
689 struct chromeec_command cec_cmd;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800690 struct ec_response_get_version cec_resp = {{0}};
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800691
692 printk(BIOS_DEBUG, "Google Chrome EC: Initializing keyboard.\n");
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800693
694 google_chromeec_hello();
695
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800696 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
697 cec_cmd.cmd_version = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800698 cec_cmd.cmd_data_out = &cec_resp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800699 cec_cmd.cmd_size_in = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800700 cec_cmd.cmd_size_out = sizeof(cec_resp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700701 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800702 google_chromeec_command(&cec_cmd);
703
704 if (cec_cmd.cmd_code) {
705 printk(BIOS_DEBUG,
706 "Google Chrome EC: version command failed!\n");
707 } else {
708 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Hung-Te Lin76720d02013-04-15 18:06:32 +0800709 printk(BIOS_DEBUG, " ro: %s\n", cec_resp.version_string_ro);
710 printk(BIOS_DEBUG, " rw: %s\n", cec_resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800711 printk(BIOS_DEBUG, " running image: %d\n",
Hung-Te Lin76720d02013-04-15 18:06:32 +0800712 cec_resp.current_image);
713 ec_image_type = cec_resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800714 }
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800715}
716
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800717int google_ec_running_ro(void)
718{
719 return (ec_image_type == EC_IMAGE_RO);
720}
721#endif /* ! __SMM__ */
722
723#endif /* ! __PRE_RAM__ */