blob: 4d47982aa6753aa7f824466b02e548cd0f9de6f1 [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>
Furquan Shaikh0325dc62016-07-25 13:02:36 -070029#include <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{
37 uint32_t *events;
38
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{
51 uint32_t *events = cbmem_find(CBMEM_ID_EC_HOSTEVENT);
52 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 */
114static u32 google_chromeec_get_mask(u8 type)
115{
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
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700133static int google_chromeec_set_mask(u8 type, u32 mask)
134{
135 struct ec_params_host_event_mask req;
136 struct ec_response_host_event_mask rsp;
137 struct chromeec_command cmd;
138
139 req.mask = mask;
140 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
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800151u32 google_chromeec_get_events_b(void)
152{
153 return google_chromeec_get_mask(EC_CMD_HOST_EVENT_GET_B);
154}
155
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700156int google_chromeec_clear_events_b(u32 mask)
157{
158 printk(BIOS_DEBUG, "Chrome EC: clear events_b mask to 0x%08x\n", mask);
159 return google_chromeec_set_mask(
160 EC_CMD_HOST_EVENT_CLEAR_B, mask);
161}
162
Duncan Laurie7378a172017-06-29 23:52:17 -0700163/* Get the current device event mask */
164uint32_t google_chromeec_get_device_enabled_events(void)
165{
166 struct ec_params_device_event req;
167 struct ec_response_device_event rsp;
168 struct chromeec_command cmd;
169
170 req.param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS;
171 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
172 cmd.cmd_version = 0;
173 cmd.cmd_data_in = &req;
174 cmd.cmd_size_in = sizeof(req);
175 cmd.cmd_data_out = &rsp;
176 cmd.cmd_size_out = sizeof(rsp);
177 cmd.cmd_dev_index = 0;
178
179 if (google_chromeec_command(&cmd) == 0)
180 return rsp.event_mask;
181 return 0;
182}
183
184/* Set the current device event mask */
185int google_chromeec_set_device_enabled_events(uint32_t mask)
186{
187 struct ec_params_device_event req;
188 struct ec_response_device_event rsp;
189 struct chromeec_command cmd;
190
191 req.event_mask = mask;
192 req.param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS;
193 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
194 cmd.cmd_version = 0;
195 cmd.cmd_data_in = &req;
196 cmd.cmd_size_in = sizeof(req);
197 cmd.cmd_data_out = &rsp;
198 cmd.cmd_size_out = sizeof(rsp);
199 cmd.cmd_dev_index = 0;
200
201 return google_chromeec_command(&cmd);
202}
203
204/* Read and clear pending device events */
205uint32_t google_chromeec_get_device_current_events(void)
206{
207 struct ec_params_device_event req;
208 struct ec_response_device_event rsp;
209 struct chromeec_command cmd;
210
211 req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
212 cmd.cmd_code = EC_CMD_DEVICE_EVENT;
213 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);
218 cmd.cmd_dev_index = 0;
219
220 if (google_chromeec_command(&cmd) == 0)
221 return rsp.event_mask;
222 return 0;
223}
224
225void google_chromeec_log_device_events(uint32_t mask)
226{
227 uint32_t events;
228 int i;
229
230 if (!IS_ENABLED(CONFIG_ELOG))
231 return;
232
233 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
234 return;
235
236 events = google_chromeec_get_device_current_events() & mask;
237 printk(BIOS_INFO, "EC Device Events: 0x%08x\n", events);
238
239 for (i = 0; i < sizeof(events) * 8; i++) {
240 if (EC_DEVICE_EVENT_MASK(i) & events)
241 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
242 }
243}
244
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800245int google_chromeec_check_feature(int feature)
246{
247 struct chromeec_command cmd;
248 struct ec_response_get_features r;
249
250 cmd.cmd_code = EC_CMD_GET_FEATURES;
251 cmd.cmd_version = 0;
252 cmd.cmd_size_in = 0;
253 cmd.cmd_data_out = &r;
254 cmd.cmd_size_out = sizeof(r);
255 cmd.cmd_dev_index = 0;
256
257 if (google_chromeec_command(&cmd) != 0)
258 return -1;
259
260 if (feature >= 8 * sizeof(r.flags))
261 return -1;
262
263 return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
264}
265
Simon Glass78659322016-06-10 20:58:24 -0600266#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_RTC)
267int rtc_get(struct rtc_time *time)
268{
269 struct chromeec_command cmd;
270 struct ec_response_rtc r;
271
272 cmd.cmd_code = EC_CMD_RTC_GET_VALUE;
273 cmd.cmd_version = 0;
274 cmd.cmd_size_in = 0;
275 cmd.cmd_data_out = &r;
276 cmd.cmd_size_out = sizeof(r);
277 cmd.cmd_dev_index = 0;
278
279 if (google_chromeec_command(&cmd) != 0)
280 return -1;
281
282 return rtc_to_tm(r.time, time);
283}
284#endif
285
Aaron Durbine68d22f2017-05-04 12:32:52 -0500286int google_chromeec_reboot(int dev_idx, enum ec_reboot_cmd type, uint8_t flags)
287{
288 struct ec_params_reboot_ec reboot_ec = {
289 .cmd = type,
290 .flags = flags,
291 };
292 struct ec_response_get_version cec_resp = { };
293 struct chromeec_command cec_cmd = {
294 .cmd_code = EC_CMD_REBOOT_EC,
295 .cmd_version = 0,
296 .cmd_data_in = &reboot_ec,
297 .cmd_data_out = &cec_resp,
298 .cmd_size_in = sizeof(reboot_ec),
299 .cmd_size_out = 0, /* ignore response, if any */
300 .cmd_dev_index = dev_idx,
301 };
302
303 return google_chromeec_command(&cec_cmd);
304}
305
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700306#ifndef __SMM__
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700307#ifdef __PRE_RAM__
Aaron Durbin9f1a7cf2014-01-09 14:28:05 -0600308void google_chromeec_check_ec_image(int expected_type)
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700309{
310 struct chromeec_command cec_cmd;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700311 struct ec_response_get_version cec_resp = { { 0 } };
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700312
313 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
314 cec_cmd.cmd_version = 0;
315 cec_cmd.cmd_data_out = &cec_resp;
316 cec_cmd.cmd_size_in = 0;
317 cec_cmd.cmd_size_out = sizeof(cec_resp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700318 cec_cmd.cmd_dev_index = 0;
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700319 google_chromeec_command(&cec_cmd);
320
Aaron Durbin9f1a7cf2014-01-09 14:28:05 -0600321 if (cec_cmd.cmd_code || cec_resp.current_image != expected_type) {
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700322 /* Reboot the EC and make it come back in RO mode */
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700323 printk(BIOS_DEBUG, "Rebooting with EC in RO mode:\n");
Duncan Lauriebf5407c2014-08-29 15:32:55 -0700324 post_code(0); /* clear current post code */
Aaron Durbin96a43172017-02-06 10:08:45 -0600325 /* Let the platform prepare for the EC taking out the system power. */
326 if (IS_ENABLED(CONFIG_VBOOT))
327 vboot_platform_prepare_reboot();
Aaron Durbine68d22f2017-05-04 12:32:52 -0500328 google_chromeec_reboot(0, EC_REBOOT_COLD, 0);
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700329 udelay(1000);
330 hard_reset();
Patrick Georgi546953c2014-11-29 10:38:17 +0100331 halt();
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700332 }
333}
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700334
Furquan Shaikh0325dc62016-07-25 13:02:36 -0700335/* Check for recovery mode and ensure PD/EC is in RO */
Aaron Durbin9f1a7cf2014-01-09 14:28:05 -0600336void google_chromeec_early_init(void)
337{
Furquan Shaikh0325dc62016-07-25 13:02:36 -0700338 if (!IS_ENABLED(CONFIG_CHROMEOS) || !vboot_recovery_mode_enabled())
339 return;
Duncan Laurieab40b912015-09-04 10:14:18 -0700340
Furquan Shaikh0325dc62016-07-25 13:02:36 -0700341 /* Check USB PD chip state first */
342 if (IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_PD))
343 google_chromeec_check_pd_image(EC_IMAGE_RO);
344
345 /* If in recovery ensure EC is running RO firmware. */
346 google_chromeec_check_ec_image(EC_IMAGE_RO);
Aaron Durbin9f1a7cf2014-01-09 14:28:05 -0600347}
348
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700349void google_chromeec_check_pd_image(int expected_type)
350{
351 struct chromeec_command cec_cmd;
352 struct ec_response_get_version cec_resp = { { 0 } };
353
354 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
355 cec_cmd.cmd_version = 0;
356 cec_cmd.cmd_data_out = &cec_resp;
357 cec_cmd.cmd_size_in = 0;
358 cec_cmd.cmd_size_out = sizeof(cec_resp);
359 cec_cmd.cmd_dev_index = 1; /* PD */
360 google_chromeec_command(&cec_cmd);
361
362 if (cec_cmd.cmd_code || cec_resp.current_image != expected_type) {
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700363 /* Reboot the PD and make it come back in RO mode */
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700364 printk(BIOS_DEBUG, "Rebooting PD to RO mode\n");
Aaron Durbine68d22f2017-05-04 12:32:52 -0500365 google_chromeec_reboot(1 /* PD */, EC_REBOOT_COLD, 0);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700366 udelay(1000);
367 }
368}
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700369#endif
370
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700371u16 google_chromeec_get_board_version(void)
372{
373 struct chromeec_command cmd;
374 struct ec_response_board_version board_v;
375
376 cmd.cmd_code = EC_CMD_GET_BOARD_VERSION;
377 cmd.cmd_version = 0;
378 cmd.cmd_size_in = 0;
379 cmd.cmd_size_out = sizeof(board_v);
380 cmd.cmd_data_out = &board_v;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700381 cmd.cmd_dev_index = 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700382
383 if (google_chromeec_command(&cmd) != 0)
384 return 0;
385
386 return board_v.board_version;
387}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700388
Patrick Georgi69206d92017-07-31 14:20:07 +0200389u32 google_chromeec_get_sku_id(void)
390{
391 struct chromeec_command cmd;
392 struct ec_response_sku_id sku_v;
393
394 cmd.cmd_code = EC_CMD_GET_SKU_ID;
395 cmd.cmd_version = 0;
396 cmd.cmd_size_in = 0;
397 cmd.cmd_size_out = sizeof(sku_v);
398 cmd.cmd_data_out = &sku_v;
399 cmd.cmd_dev_index = 0;
400
401 if (google_chromeec_command(&cmd) != 0)
402 return 0;
403
404 return sku_v.sku_id;
405}
406
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700407int google_chromeec_vbnv_context(int is_read, uint8_t *data, int len)
408{
409 struct chromeec_command cec_cmd;
410 struct ec_params_vbnvcontext cmd_vbnvcontext;
411 struct ec_response_vbnvcontext rsp_vbnvcontext;
Julius Werner02e847b2015-02-20 13:36:11 -0800412 int retries = 3;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700413
414 if (len != EC_VBNV_BLOCK_SIZE)
415 return -1;
416
Patrick Georgif5060312015-10-13 22:14:22 +0200417retry:
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700418 cec_cmd.cmd_code = EC_CMD_VBNV_CONTEXT;
419 cec_cmd.cmd_version = EC_VER_VBNV_CONTEXT;
420 cec_cmd.cmd_data_in = &cmd_vbnvcontext;
421 cec_cmd.cmd_data_out = &rsp_vbnvcontext;
422 cec_cmd.cmd_size_in = sizeof(cmd_vbnvcontext);
Aaron Durbin3e497382014-08-06 14:28:52 -0500423 cec_cmd.cmd_size_out = is_read ? sizeof(rsp_vbnvcontext) : 0;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700424 cec_cmd.cmd_dev_index = 0;
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700425
426 cmd_vbnvcontext.op = is_read ? EC_VBNV_CONTEXT_OP_READ :
427 EC_VBNV_CONTEXT_OP_WRITE;
428
429 if (!is_read)
430 memcpy(&cmd_vbnvcontext.block, data, EC_VBNV_BLOCK_SIZE);
431
Julius Werner02e847b2015-02-20 13:36:11 -0800432 if (google_chromeec_command(&cec_cmd)) {
433 printk(BIOS_ERR, "ERROR: failed to %s vbnv_ec context: %d\n",
434 is_read ? "read" : "write", (int)cec_cmd.cmd_code);
435 mdelay(10); /* just in case */
436 if (--retries)
437 goto retry;
438 }
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700439
440 if (is_read)
441 memcpy(data, &rsp_vbnvcontext.block, EC_VBNV_BLOCK_SIZE);
442
443 return cec_cmd.cmd_code;
444}
445
Duncan Laurie7cced0d2013-06-04 10:03:34 -0700446#endif /* ! __SMM__ */
447
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800448#ifndef __PRE_RAM__
449
Gabe Black9f96aa62013-06-28 14:24:33 -0700450int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
451 uint8_t *buffer, int len, int is_read)
452{
453 union {
454 struct ec_params_i2c_passthru p;
455 uint8_t outbuf[EC_HOST_PARAM_SIZE];
456 } params;
457 union {
458 struct ec_response_i2c_passthru r;
459 uint8_t inbuf[EC_HOST_PARAM_SIZE];
460 } response;
461 struct ec_params_i2c_passthru *p = &params.p;
462 struct ec_response_i2c_passthru *r = &response.r;
463 struct ec_params_i2c_passthru_msg *msg = p->msg;
464 struct chromeec_command cmd;
465 uint8_t *pdata;
466 int read_len, write_len;
467 int size;
468 int rv;
469
470 p->port = 0;
471
472 if (alen != 1) {
473 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
474 return -1;
475 }
476 if (is_read) {
477 read_len = len;
478 write_len = alen;
479 p->num_msgs = 2;
480 } else {
481 read_len = 0;
482 write_len = alen + len;
483 p->num_msgs = 1;
484 }
485
486 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
487 if (size + write_len > sizeof(params)) {
488 printk(BIOS_ERR, "Params too large for buffer\n");
489 return -1;
490 }
491 if (sizeof(*r) + read_len > sizeof(response)) {
492 printk(BIOS_ERR, "Read length too big for buffer\n");
493 return -1;
494 }
495
496 /* Create a message to write the register address and optional data */
497 pdata = (uint8_t *)p + size;
498 msg->addr_flags = chip;
499 msg->len = write_len;
500 pdata[0] = addr;
501 if (!is_read)
502 memcpy(pdata + 1, buffer, len);
503 msg++;
504
505 if (read_len) {
506 msg->addr_flags = chip | EC_I2C_FLAG_READ;
507 msg->len = read_len;
508 }
509
510 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
511 cmd.cmd_version = 0;
512 cmd.cmd_data_in = p;
513 cmd.cmd_size_in = size + write_len;
514 cmd.cmd_data_out = r;
515 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700516 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -0700517 rv = google_chromeec_command(&cmd);
518 if (rv != 0)
519 return rv;
520
521 /* Parse response */
522 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
523 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
524 r->i2c_status);
525 return -1;
526 }
527
528 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
529 printk(BIOS_ERR, "Truncated read response\n");
530 return -1;
531 }
532
533 if (read_len)
534 memcpy(buffer, r->data, read_len);
535
536 return 0;
537}
538
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800539int google_chromeec_set_sci_mask(u32 mask)
540{
541 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%08x\n", mask);
542 return google_chromeec_set_mask(
543 EC_CMD_HOST_EVENT_SET_SCI_MASK, mask);
544}
545
546int google_chromeec_set_smi_mask(u32 mask)
547{
548 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%08x\n", mask);
549 return google_chromeec_set_mask(
550 EC_CMD_HOST_EVENT_SET_SMI_MASK, mask);
551}
552
553int google_chromeec_set_wake_mask(u32 mask)
554{
555 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%08x\n", mask);
556 return google_chromeec_set_mask(
557 EC_CMD_HOST_EVENT_SET_WAKE_MASK, mask);
558}
559
560u32 google_chromeec_get_wake_mask(void)
561{
562 return google_chromeec_get_mask(
563 EC_CMD_HOST_EVENT_GET_WAKE_MASK);
564}
565
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800566void google_chromeec_log_events(u32 mask)
567{
Martin Rothf5c35182017-06-24 14:09:38 -0600568#if IS_ENABLED(CONFIG_ELOG)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800569 u8 event;
Duncan Laurieb12e9be2014-09-29 13:04:06 -0700570 u32 wake_mask;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800571
Duncan Laurieb12e9be2014-09-29 13:04:06 -0700572 /* Set wake mask so events will be read from ACPI interface */
573 wake_mask = google_chromeec_get_wake_mask();
574 google_chromeec_set_wake_mask(mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800575
576 while ((event = google_chromeec_get_event()) != 0) {
577 if (EC_HOST_EVENT_MASK(event) & mask)
578 elog_add_event_byte(ELOG_TYPE_EC_EVENT, event);
579 }
Duncan Laurieb12e9be2014-09-29 13:04:06 -0700580
581 google_chromeec_set_wake_mask(wake_mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800582#endif
583}
584
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800585int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode)
586{
587 struct chromeec_command cmd;
588 struct ec_params_usb_charge_set_mode set_mode = {
589 .usb_port_id = port_id,
590 .mode = mode,
591 };
592
593 cmd.cmd_code = EC_CMD_USB_CHARGE_SET_MODE;
594 cmd.cmd_version = 0;
595 cmd.cmd_size_in = sizeof(set_mode);
596 cmd.cmd_data_in = &set_mode;
597 cmd.cmd_size_out = 0;
598 cmd.cmd_data_out = NULL;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700599 cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800600
601 return google_chromeec_command(&cmd);
602}
603
Julius Wernerea79d2b2016-11-21 20:14:07 -0800604int google_chromeec_set_usb_pd_role(u8 port, enum usb_pd_control_role role)
605{
606 struct ec_params_usb_pd_control req = {
607 .port = port,
608 .role = role,
609 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
610 .swap = USB_PD_CTRL_SWAP_NONE,
611 };
612 struct ec_response_usb_pd_control rsp;
613 struct chromeec_command cmd = {
614 .cmd_code = EC_CMD_USB_PD_CONTROL,
615 .cmd_version = 0,
616 .cmd_data_in = &req,
617 .cmd_size_in = sizeof(req),
618 .cmd_data_out = &rsp,
619 .cmd_size_out = sizeof(rsp),
620 .cmd_dev_index = 0,
621 };
622
623 return google_chromeec_command(&cmd);
624}
625
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800626#ifndef __SMM__
627
628static
629int google_chromeec_hello(void)
630{
631 struct chromeec_command cec_cmd;
632 struct ec_params_hello cmd_hello;
633 struct ec_response_hello rsp_hello;
634 cmd_hello.in_data = 0x10203040;
635 cec_cmd.cmd_code = EC_CMD_HELLO;
636 cec_cmd.cmd_version = 0;
637 cec_cmd.cmd_data_in = &cmd_hello.in_data;
638 cec_cmd.cmd_data_out = &rsp_hello.out_data;
639 cec_cmd.cmd_size_in = sizeof(cmd_hello.in_data);
640 cec_cmd.cmd_size_out = sizeof(rsp_hello.out_data);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700641 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800642 google_chromeec_command(&cec_cmd);
643 printk(BIOS_DEBUG, "Google Chrome EC: Hello got back %x status (%x)\n",
644 rsp_hello.out_data, cec_cmd.cmd_code);
645 return cec_cmd.cmd_code;
646}
647
648static int ec_image_type; /* Cached EC image type (ro or rw). */
649
Hung-Te Lin76720d02013-04-15 18:06:32 +0800650void google_chromeec_init(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800651{
652 struct chromeec_command cec_cmd;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800653 struct ec_response_get_version cec_resp = {{0}};
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800654
655 printk(BIOS_DEBUG, "Google Chrome EC: Initializing keyboard.\n");
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800656
657 google_chromeec_hello();
658
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800659 cec_cmd.cmd_code = EC_CMD_GET_VERSION;
660 cec_cmd.cmd_version = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800661 cec_cmd.cmd_data_out = &cec_resp;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800662 cec_cmd.cmd_size_in = 0;
Hung-Te Lin76720d02013-04-15 18:06:32 +0800663 cec_cmd.cmd_size_out = sizeof(cec_resp);
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700664 cec_cmd.cmd_dev_index = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800665 google_chromeec_command(&cec_cmd);
666
667 if (cec_cmd.cmd_code) {
668 printk(BIOS_DEBUG,
669 "Google Chrome EC: version command failed!\n");
670 } else {
671 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Hung-Te Lin76720d02013-04-15 18:06:32 +0800672 printk(BIOS_DEBUG, " ro: %s\n", cec_resp.version_string_ro);
673 printk(BIOS_DEBUG, " rw: %s\n", cec_resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800674 printk(BIOS_DEBUG, " running image: %d\n",
Hung-Te Lin76720d02013-04-15 18:06:32 +0800675 cec_resp.current_image);
676 ec_image_type = cec_resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800677 }
678
679 if (cec_cmd.cmd_code ||
Furquan Shaikh0325dc62016-07-25 13:02:36 -0700680 (vboot_recovery_mode_enabled() &&
Hung-Te Lin76720d02013-04-15 18:06:32 +0800681 (cec_resp.current_image != EC_IMAGE_RO))) {
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800682 /* Reboot the EC and make it come back in RO mode */
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800683 printk(BIOS_DEBUG, "Rebooting with EC in RO mode:\n");
Duncan Lauriebf5407c2014-08-29 15:32:55 -0700684 post_code(0); /* clear current post code */
Aaron Durbine68d22f2017-05-04 12:32:52 -0500685 google_chromeec_reboot(0, EC_REBOOT_COLD, 0);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800686 udelay(1000);
687 hard_reset();
Patrick Georgi546953c2014-11-29 10:38:17 +0100688 halt();
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800689 }
690
691}
692
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800693int google_ec_running_ro(void)
694{
695 return (ec_image_type == EC_IMAGE_RO);
696}
697#endif /* ! __SMM__ */
698
699#endif /* ! __PRE_RAM__ */