blob: fbb0033d59fcbaa7fb43c6583cf94b7a19ca01a1 [file] [log] [blame]
Angel Pons210a0082020-04-02 23:48:24 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauerd6682e82013-02-21 15:39:35 -08002
3#include <stdint.h>
Stefan Reinaueraaaf6892013-08-29 15:57:11 -07004#include <string.h>
Jenny TC1dfc2c32017-12-14 14:24:39 +05305#include <assert.h>
Tim Wawrzynczake6078292020-01-22 15:22:18 -07006#include <console/console.h>
Stefan Reinauerd6682e82013-02-21 15:39:35 -08007#include <delay.h>
Tim Wawrzynczake6078292020-01-22 15:22:18 -07008#include <device/device.h>
9#include <device/path.h>
Furquan Shaikhbce8bb62016-11-11 13:57:55 -080010#include <elog.h>
Simon Glass78659322016-06-10 20:58:24 -060011#include <rtc.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020012#include <security/vboot/vboot_common.h>
Tim Wawrzynczake6078292020-01-22 15:22:18 -070013#include <stdlib.h>
Daisuke Nojiriebb86be2018-01-26 17:36:44 -080014#include <timer.h>
Edward O'Callaghanb57fef92014-06-17 20:13:08 +100015
Stefan Reinauerd6682e82013-02-21 15:39:35 -080016#include "ec.h"
Stefan Reinauerd6682e82013-02-21 15:39:35 -080017
Caveh Jalalibeaa8f892022-11-01 01:28:31 -070018#define CROS_EC_COMMAND_INFO const void
19#define CROS_EC_COMMAND(h, c, v, p, ps, r, rs) \
20 google_chromeec_command(&(struct chromeec_command) { \
21 .cmd_code = (c), \
22 .cmd_version = (v), \
23 .cmd_data_in = (p), \
24 .cmd_size_in = (ps), \
25 .cmd_data_out = (r), \
26 .cmd_size_out = (rs), \
27 .cmd_dev_index = 0, \
28 })
29
30#include "ec_cmd_api.h"
31
32/*
33 * coreboot only supports a single platform EC, so there is no need to
34 * provide a context handle for the EC.
35 */
36#define PLAT_EC NULL
37
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
Hung-Te Lin6bfbb332013-04-15 18:27:24 +080086uint8_t google_chromeec_calc_checksum(const uint8_t *data, int size)
87{
88 int csum;
89
90 for (csum = 0; size > 0; data++, size--)
91 csum += *data;
92 return (uint8_t)(csum & 0xff);
93}
94
Stefan Reinauerd6682e82013-02-21 15:39:35 -080095int google_chromeec_kbbacklight(int percent)
96{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -070097 const struct ec_params_pwm_set_keyboard_backlight params = {
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -060098 .percent = percent % 101,
99 };
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800100
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700101 if (ec_cmd_pwm_set_keyboard_backlight(PLAT_EC, &params) != 0)
Caveh Jalali2320c032022-11-02 19:55:39 -0700102 return -1;
103
104 return 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800105}
106
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600107void google_chromeec_post(uint8_t postcode)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800108{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600109 /* backlight is a percent. postcode is a uint8_t.
110 * Convert the uint8_t to %.
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800111 */
112 postcode = (postcode/4) + (postcode/8);
113 google_chromeec_kbbacklight(postcode);
114}
115
116/*
117 * Query the EC for specified mask indicating enabled events.
118 * The EC maintains separate event masks for SMI, SCI and WAKE.
119 */
Jenny TC1dfc2c32017-12-14 14:24:39 +0530120static int google_chromeec_uhepi_cmd(uint8_t mask, uint8_t action,
121 uint64_t *value)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800122{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530123 int ret;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600124 struct ec_params_host_event params = {
125 .action = action,
126 .mask_type = mask,
127 };
128 struct ec_response_host_event resp = {};
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800129
Jenny TC1dfc2c32017-12-14 14:24:39 +0530130 if (action != EC_HOST_EVENT_GET)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600131 params.value = *value;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530132 else
133 *value = 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800134
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700135 ret = ec_cmd_host_event(PLAT_EC, &params, &resp);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530136
137 if (action != EC_HOST_EVENT_GET)
138 return ret;
139 if (ret == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600140 *value = resp.value;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530141 return ret;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800142}
143
Jenny TC1dfc2c32017-12-14 14:24:39 +0530144static int google_chromeec_handle_non_uhepi_cmd(uint8_t hcmd, uint8_t action,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600145 uint64_t *value)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700146{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530147 int ret = -1;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600148 struct ec_params_host_event_mask params = {};
149 struct ec_response_host_event_mask resp = {};
150 struct chromeec_command cmd = {
151 .cmd_code = hcmd,
152 .cmd_version = 0,
153 .cmd_data_in = &params,
154 .cmd_size_in = sizeof(params),
155 .cmd_data_out = &resp,
156 .cmd_size_out = sizeof(resp),
157 .cmd_dev_index = 0,
158 };
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700159
Jenny TC1dfc2c32017-12-14 14:24:39 +0530160 if (hcmd == INVALID_HCMD)
161 return ret;
162
163 if (action != EC_HOST_EVENT_GET)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600164 params.mask = (uint32_t)*value;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530165 else
166 *value = 0;
167
Jenny TC1dfc2c32017-12-14 14:24:39 +0530168 ret = google_chromeec_command(&cmd);
169
170 if (action != EC_HOST_EVENT_GET)
171 return ret;
172 if (ret == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600173 *value = resp.mask;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530174
175 return ret;
176}
177
178bool google_chromeec_is_uhepi_supported(void)
179{
180#define UHEPI_SUPPORTED 1
181#define UHEPI_NOT_SUPPORTED 2
182
Arthur Heymans95b3f282019-11-20 21:23:16 +0100183 static int uhepi_support;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530184
185 if (!uhepi_support) {
186 uhepi_support = google_chromeec_check_feature
Matt DeVillier41328932018-03-04 00:05:12 -0600187 (EC_FEATURE_UNIFIED_WAKE_MASKS) > 0 ? UHEPI_SUPPORTED :
Jenny TC1dfc2c32017-12-14 14:24:39 +0530188 UHEPI_NOT_SUPPORTED;
189 printk(BIOS_DEBUG, "Chrome EC: UHEPI %s\n",
190 uhepi_support == UHEPI_SUPPORTED ?
191 "supported" : "not supported");
192 }
193 return uhepi_support == UHEPI_SUPPORTED;
194}
195
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600196static uint64_t google_chromeec_get_mask(uint8_t type)
Jenny TC1dfc2c32017-12-14 14:24:39 +0530197{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600198 uint64_t value = 0;
Jenny TC1dfc2c32017-12-14 14:24:39 +0530199
200 if (google_chromeec_is_uhepi_supported()) {
201 google_chromeec_uhepi_cmd(type, EC_HOST_EVENT_GET, &value);
202 } else {
203 assert(type < ARRAY_SIZE(event_map));
204 google_chromeec_handle_non_uhepi_cmd(
205 event_map[type].get_cmd,
206 EC_HOST_EVENT_GET, &value);
207 }
208 return value;
209}
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600210
211static int google_chromeec_clear_mask(uint8_t type, uint64_t mask)
Jenny TC1dfc2c32017-12-14 14:24:39 +0530212{
213 if (google_chromeec_is_uhepi_supported())
214 return google_chromeec_uhepi_cmd(type,
215 EC_HOST_EVENT_CLEAR, &mask);
216
217 assert(type < ARRAY_SIZE(event_map));
218 return google_chromeec_handle_non_uhepi_cmd(
219 event_map[type].clear_cmd,
220 EC_HOST_EVENT_CLEAR, &mask);
221}
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600222
Bill XIEac1362502022-07-08 16:53:21 +0800223static int google_chromeec_set_mask(uint8_t type, uint64_t mask)
Jenny TC1dfc2c32017-12-14 14:24:39 +0530224{
225 if (google_chromeec_is_uhepi_supported())
226 return google_chromeec_uhepi_cmd(type,
227 EC_HOST_EVENT_SET, &mask);
228
229 assert(type < ARRAY_SIZE(event_map));
230 return google_chromeec_handle_non_uhepi_cmd(
231 event_map[type].set_cmd,
232 EC_HOST_EVENT_SET, &mask);
233}
234
235static int google_chromeec_set_s3_lazy_wake_mask(uint64_t mask)
236{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800237 printk(BIOS_DEBUG, "Chrome EC: Set S3 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530238 mask);
239 return google_chromeec_set_mask
240 (EC_HOST_EVENT_LAZY_WAKE_MASK_S3, mask);
241}
242
243static int google_chromeec_set_s5_lazy_wake_mask(uint64_t mask)
244{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800245 printk(BIOS_DEBUG, "Chrome EC: Set S5 LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530246 mask);
247 return google_chromeec_set_mask
248 (EC_HOST_EVENT_LAZY_WAKE_MASK_S5, mask);
249}
250
251static int google_chromeec_set_s0ix_lazy_wake_mask(uint64_t mask)
252{
Furquan Shaikh8389fe62018-02-23 16:07:25 -0800253 printk(BIOS_DEBUG, "Chrome EC: Set S0iX LAZY WAKE mask to 0x%016llx\n",
Jenny TC1dfc2c32017-12-14 14:24:39 +0530254 mask);
255 return google_chromeec_set_mask
256 (EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, mask);
257}
258static void google_chromeec_set_lazy_wake_masks(uint64_t s5_mask,
259 uint64_t s3_mask, uint64_t s0ix_mask)
260{
261 if (google_chromeec_set_s5_lazy_wake_mask(s5_mask))
262 printk(BIOS_DEBUG, "Error: Set S5 LAZY WAKE mask failed\n");
263 if (google_chromeec_set_s3_lazy_wake_mask(s3_mask))
264 printk(BIOS_DEBUG, "Error: Set S3 LAZY WAKE mask failed\n");
Paul Moy88900dc2018-09-14 15:24:23 -0600265 /*
266 * Make sure S0Ix is supported before trying to set up the EC's
267 * S0Ix lazy wake mask.
268 */
269 if (s0ix_mask && google_chromeec_set_s0ix_lazy_wake_mask(s0ix_mask))
Jenny TC1dfc2c32017-12-14 14:24:39 +0530270 printk(BIOS_DEBUG, "Error: Set S0iX LAZY WAKE mask failed\n");
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700271}
272
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800273uint64_t google_chromeec_get_events_b(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800274{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530275 return google_chromeec_get_mask(EC_HOST_EVENT_B);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800276}
277
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800278int google_chromeec_clear_events_b(uint64_t mask)
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700279{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530280 printk(BIOS_DEBUG,
281 "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
282 return google_chromeec_clear_mask(EC_HOST_EVENT_B, mask);
Sheng-Liang Song1d6560f2014-04-30 15:46:45 -0700283}
284
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700285int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
286{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700287 return ec_cmd_get_next_event(PLAT_EC, event);
Furquan Shaikhe01bf642017-10-13 10:59:51 -0700288}
289
Duncan Laurie7378a172017-06-29 23:52:17 -0700290/* Get the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800291uint64_t google_chromeec_get_device_enabled_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700292{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700293 const struct ec_params_device_event params = {
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600294 .param = EC_DEVICE_EVENT_PARAM_GET_ENABLED_EVENTS,
295 };
296 struct ec_response_device_event resp = {};
Duncan Laurie7378a172017-06-29 23:52:17 -0700297
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700298 if (ec_cmd_device_event(PLAT_EC, &params, &resp) == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600299 return resp.event_mask;
300
Duncan Laurie7378a172017-06-29 23:52:17 -0700301 return 0;
302}
303
304/* Set the current device event mask */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800305int google_chromeec_set_device_enabled_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700306{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700307 const struct ec_params_device_event params = {
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600308 .event_mask = (uint32_t)mask,
309 .param = EC_DEVICE_EVENT_PARAM_SET_ENABLED_EVENTS,
310 };
311 struct ec_response_device_event resp = {};
Duncan Laurie7378a172017-06-29 23:52:17 -0700312
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700313 return ec_cmd_device_event(PLAT_EC, &params, &resp);
Duncan Laurie7378a172017-06-29 23:52:17 -0700314}
315
316/* Read and clear pending device events */
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800317uint64_t google_chromeec_get_device_current_events(void)
Duncan Laurie7378a172017-06-29 23:52:17 -0700318{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700319 const struct ec_params_device_event params = {
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600320 .param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS,
321 };
322 struct ec_response_device_event resp = {};
Duncan Laurie7378a172017-06-29 23:52:17 -0700323
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700324 if (ec_cmd_device_event(PLAT_EC, &params, &resp) == 0)
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600325 return resp.event_mask;
326
Duncan Laurie7378a172017-06-29 23:52:17 -0700327 return 0;
328}
329
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800330static void google_chromeec_log_device_events(uint64_t mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700331{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800332 uint64_t events;
Duncan Laurie7378a172017-06-29 23:52:17 -0700333 int i;
334
Julius Wernercd49cce2019-03-05 16:53:33 -0800335 if (!CONFIG(ELOG) || !mask)
Duncan Laurie7378a172017-06-29 23:52:17 -0700336 return;
337
338 if (google_chromeec_check_feature(EC_FEATURE_DEVICE_EVENT) != 1)
339 return;
340
341 events = google_chromeec_get_device_current_events() & mask;
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800342 printk(BIOS_INFO, "EC Device Events: 0x%016llx\n", events);
Duncan Laurie7378a172017-06-29 23:52:17 -0700343
344 for (i = 0; i < sizeof(events) * 8; i++) {
345 if (EC_DEVICE_EVENT_MASK(i) & events)
346 elog_add_event_byte(ELOG_TYPE_EC_DEVICE_EVENT, i);
347 }
348}
349
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800350void google_chromeec_log_events(uint64_t mask)
Furquan Shaikh2749c522017-10-04 14:01:41 -0700351{
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700352 uint64_t events;
353 int i;
Furquan Shaikh2749c522017-10-04 14:01:41 -0700354
Julius Wernercd49cce2019-03-05 16:53:33 -0800355 if (!CONFIG(ELOG))
Furquan Shaikh2749c522017-10-04 14:01:41 -0700356 return;
357
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700358 events = google_chromeec_get_events_b() & mask;
Tim Wawrzynczak7777e1c2020-07-14 13:30:46 -0600359
360 /*
361 * This loop starts at 1 because the EC_HOST_EVENT_MASK macro subtracts
362 * 1 from its argument before applying the left-shift operator. This
363 * prevents a left-shift of -1 happening, and covers the entire 64-bit
364 * range of the event mask.
365 */
366 for (i = 1; i <= sizeof(events) * 8; i++) {
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700367 if (EC_HOST_EVENT_MASK(i) & events)
368 elog_add_event_byte(ELOG_TYPE_EC_EVENT, i);
Furquan Shaikh1432cbc2017-10-13 11:31:35 -0700369 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700370
Ravi Chandra Sadineni6ae8b502019-06-18 10:10:19 -0700371 google_chromeec_clear_events_b(events);
Furquan Shaikh2749c522017-10-04 14:01:41 -0700372}
373
374void google_chromeec_events_init(const struct google_chromeec_event_info *info,
375 bool is_s3_wakeup)
376{
377 if (is_s3_wakeup) {
378 google_chromeec_log_events(info->log_events |
379 info->s3_wake_events);
380
381 /* Log and clear device events that may wake the system. */
382 google_chromeec_log_device_events(info->s3_device_events);
383
384 /* Disable SMI and wake events. */
385 google_chromeec_set_smi_mask(0);
386
Furquan Shaikh2749c522017-10-04 14:01:41 -0700387 /* Restore SCI event mask. */
388 google_chromeec_set_sci_mask(info->sci_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530389
390 } else {
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700391 google_chromeec_set_smi_mask(info->smi_events);
392
Furquan Shaikh2749c522017-10-04 14:01:41 -0700393 google_chromeec_log_events(info->log_events |
394 info->s5_wake_events);
Furquan Shaikh1a5b7c62018-05-30 11:51:23 -0700395
Jenny TC1dfc2c32017-12-14 14:24:39 +0530396 if (google_chromeec_is_uhepi_supported())
397 google_chromeec_set_lazy_wake_masks
398 (info->s5_wake_events,
399 info->s3_wake_events,
400 info->s0ix_wake_events);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530401 }
Furquan Shaikh2749c522017-10-04 14:01:41 -0700402
403 /* Clear wake event mask. */
404 google_chromeec_set_wake_mask(0);
405}
406
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800407int google_chromeec_check_feature(int feature)
408{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600409 struct ec_response_get_features resp = {};
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800410
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700411 if (ec_cmd_get_features(PLAT_EC, &resp) != 0)
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800412 return -1;
413
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600414 if (feature >= 8 * sizeof(resp.flags))
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800415 return -1;
416
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600417 return resp.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
Duncan Lauriee2cea4f2015-12-01 19:14:09 -0800418}
419
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600420int google_chromeec_get_cmd_versions(int command, uint32_t *pmask)
421{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700422 const struct ec_params_get_cmd_versions_v1 params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600423 .cmd = command,
424 };
425 struct ec_response_get_cmd_versions resp = {};
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600426
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700427 if (ec_cmd_get_cmd_versions_v1(PLAT_EC, &params, &resp) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600428 return -1;
429
430 *pmask = resp.version_mask;
431 return 0;
432}
433
434int google_chromeec_get_vboot_hash(uint32_t offset,
435 struct ec_response_vboot_hash *resp)
436{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700437 const struct ec_params_vboot_hash params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600438 .cmd = EC_VBOOT_HASH_GET,
439 .offset = offset,
440 };
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600441
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700442 if (ec_cmd_vboot_hash(PLAT_EC, &params, resp) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600443 return -1;
444
445 return 0;
446}
447
448int google_chromeec_start_vboot_hash(enum ec_vboot_hash_type hash_type,
449 uint32_t hash_offset,
450 struct ec_response_vboot_hash *resp)
451{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700452 const struct ec_params_vboot_hash params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600453 .cmd = EC_VBOOT_HASH_START,
454 .hash_type = hash_type,
455 .nonce_size = 0,
456 .offset = hash_offset,
457 };
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600458
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700459 if (ec_cmd_vboot_hash(PLAT_EC, &params, resp) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600460 return -1;
461
462 return 0;
463}
464
465int google_chromeec_flash_protect(uint32_t mask, uint32_t flags,
466 struct ec_response_flash_protect *resp)
467{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700468 const struct ec_params_flash_protect params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600469 .mask = mask,
470 .flags = flags,
471 };
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600472
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700473 if (ec_cmd_flash_protect_v1(PLAT_EC, &params, resp) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600474 return -1;
475
476 return 0;
477}
478
479int google_chromeec_flash_region_info(enum ec_flash_region region,
480 uint32_t *offset, uint32_t *size)
481{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700482 const struct ec_params_flash_region_info params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600483 .region = region,
484 };
485 struct ec_response_flash_region_info resp = {};
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600486
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700487 if (ec_cmd_flash_region_info_v1(PLAT_EC, &params, &resp) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600488 return -1;
489
490 if (offset)
491 *offset = resp.offset;
492 if (size)
493 *size = resp.size;
494
495 return 0;
496}
497
498int google_chromeec_flash_erase(uint32_t offset, uint32_t size)
499{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700500 const struct ec_params_flash_erase params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600501 .offset = offset,
502 .size = size,
503 };
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600504
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700505 if (ec_cmd_flash_erase(PLAT_EC, &params) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600506 return -1;
507
508 return 0;
509}
510
511int google_chromeec_flash_info(struct ec_response_flash_info *info)
512{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700513 if (ec_cmd_flash_info(PLAT_EC, info) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600514 return -1;
515
516 return 0;
517}
518
519/*
520 * Write a block into EC flash. Expects params_data to be a buffer where
521 * the first N bytes are a struct ec_params_flash_write, and the rest of it
522 * is the data to write to flash.
523*/
524int google_chromeec_flash_write_block(const uint8_t *params_data,
525 uint32_t bufsize)
526{
527 struct chromeec_command cmd = {
528 .cmd_code = EC_CMD_FLASH_WRITE,
529 .cmd_version = EC_VER_FLASH_WRITE,
530 .cmd_size_out = 0,
531 .cmd_data_out = NULL,
532 .cmd_size_in = bufsize,
533 .cmd_data_in = params_data,
534 .cmd_dev_index = 0,
535 };
536
537 assert(params_data);
538
539 return google_chromeec_command(&cmd);
540}
541
542/*
543 * EFS verification of flash.
544 */
545int google_chromeec_efs_verify(enum ec_flash_region region)
546{
547 struct ec_params_efs_verify params = {
548 .region = region,
549 };
550 struct chromeec_command cmd = {
551 .cmd_code = EC_CMD_EFS_VERIFY,
552 .cmd_version = 0,
553 .cmd_size_in = sizeof(params),
554 .cmd_data_in = &params,
555 .cmd_size_out = 0,
556 .cmd_data_out = NULL,
557 .cmd_dev_index = 0,
558 };
559 int rv;
560
561 /* It's okay if the EC doesn't support EFS */
562 rv = google_chromeec_command(&cmd);
563 if (rv != 0 && (cmd.cmd_code == EC_RES_INVALID_COMMAND))
564 return 0;
565 else if (rv != 0)
566 return -1;
567
568 return 0;
569}
570
571int google_chromeec_battery_cutoff(uint8_t flags)
572{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700573 const struct ec_params_battery_cutoff params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600574 .flags = flags,
575 };
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600576
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700577 if (ec_cmd_battery_cut_off_v1(PLAT_EC, &params) != 0)
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600578 return -1;
579
580 return 0;
581}
582
583int google_chromeec_read_limit_power_request(int *limit_power)
584{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700585 const struct ec_params_charge_state params = {
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600586 .cmd = CHARGE_STATE_CMD_GET_PARAM,
587 .get_param.param = CS_PARAM_LIMIT_POWER,
588 };
589 struct ec_response_charge_state resp = {};
590 struct chromeec_command cmd = {
591 .cmd_code = EC_CMD_CHARGE_STATE,
592 .cmd_version = 0,
593 .cmd_size_in = sizeof(params),
594 .cmd_data_in = &params,
595 .cmd_size_out = sizeof(resp),
596 .cmd_data_out = &resp,
597 .cmd_dev_index = 0,
598 };
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100599 int rv;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600600
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100601 rv = google_chromeec_command(&cmd);
Rizwan Qureshicf425782019-12-27 21:41:07 +0530602
603 if (rv != 0 && (cmd.cmd_code == EC_RES_INVALID_COMMAND ||
604 cmd.cmd_code == EC_RES_INVALID_PARAM)) {
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100605 printk(BIOS_INFO, "PARAM_LIMIT_POWER not supported by EC.\n");
606 *limit_power = 0;
607 return 0;
Rizwan Qureshicf425782019-12-27 21:41:07 +0530608 } else if (rv != 0) {
609 return -1;
Tim Wawrzynczak0d9fb552019-12-25 19:14:30 +1100610 }
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600611
612 *limit_power = resp.get_param.value;
Rizwan Qureshicf425782019-12-27 21:41:07 +0530613
614 return 0;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600615}
616
617int google_chromeec_get_protocol_info(
618 struct ec_response_get_protocol_info *resp)
619{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700620 if (ec_cmd_get_protocol_info(PLAT_EC, resp))
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600621 return -1;
622
623 return 0;
624}
625
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600626int google_chromeec_set_sku_id(uint32_t skuid)
Kevin Chiue2bb0592017-09-12 09:13:41 +0800627{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700628 const struct ec_sku_id_info params = {
Kevin Chiue2bb0592017-09-12 09:13:41 +0800629 .sku_id = skuid
630 };
Kevin Chiue2bb0592017-09-12 09:13:41 +0800631
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700632 if (ec_cmd_set_sku_id(PLAT_EC, &params) != 0)
Kevin Chiue2bb0592017-09-12 09:13:41 +0800633 return -1;
634
635 return 0;
636}
637
Julius Wernercd49cce2019-03-05 16:53:33 -0800638#if CONFIG(EC_GOOGLE_CHROMEEC_RTC)
Simon Glass78659322016-06-10 20:58:24 -0600639int rtc_get(struct rtc_time *time)
640{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600641 struct ec_response_rtc resp = {};
Simon Glass78659322016-06-10 20:58:24 -0600642
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700643 if (ec_cmd_rtc_get_value(PLAT_EC, &resp) != 0)
Simon Glass78659322016-06-10 20:58:24 -0600644 return -1;
645
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600646 return rtc_to_tm(resp.time, time);
Simon Glass78659322016-06-10 20:58:24 -0600647}
648#endif
649
Caveh Jalali603de3f2022-11-01 02:02:56 -0700650int google_chromeec_reboot(enum ec_reboot_cmd type, uint8_t flags)
Aaron Durbine68d22f2017-05-04 12:32:52 -0500651{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700652 const struct ec_params_reboot_ec params = {
Aaron Durbine68d22f2017-05-04 12:32:52 -0500653 .cmd = type,
654 .flags = flags,
655 };
Aaron Durbine68d22f2017-05-04 12:32:52 -0500656
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700657 return ec_cmd_reboot_ec(PLAT_EC, &params);
Aaron Durbine68d22f2017-05-04 12:32:52 -0500658}
659
Jonathan Brandmeyer6bffc5c2018-07-23 16:30:44 -0600660static int cbi_get_uint32(uint32_t *id, uint32_t tag)
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800661{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600662 struct ec_params_get_cbi params = {
663 .tag = tag,
664 };
Zhuohao Lee7824d9b2018-03-30 10:18:04 +0800665 uint32_t r = 0;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600666 struct chromeec_command cmd = {
667 .cmd_code = EC_CMD_GET_CROS_BOARD_INFO,
668 .cmd_version = 0,
669 .cmd_data_in = &params,
670 .cmd_data_out = &r,
671 .cmd_size_in = sizeof(params),
672 .cmd_size_out = sizeof(r),
673 .cmd_dev_index = 0,
674 };
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800675 int rv;
676
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800677 rv = google_chromeec_command(&cmd);
YH Lin40f65422019-02-26 09:56:06 -0800678 if (rv != 0)
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800679 return rv;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600680
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800681 *id = r;
682 return 0;
683}
684
685int google_chromeec_cbi_get_sku_id(uint32_t *id)
686{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800687 return cbi_get_uint32(id, CBI_TAG_SKU_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800688}
689
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600690int google_chromeec_cbi_get_fw_config(uint64_t *fw_config)
Jett Rink8db8a612020-01-14 11:41:47 -0700691{
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600692 uint32_t config;
693
694 if (cbi_get_uint32(&config, CBI_TAG_FW_CONFIG))
695 return -1;
696
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600697 *fw_config = (uint64_t)config;
Karthikeyan Ramasubramanian86728842021-02-25 00:29:14 -0700698 /*
699 * If SSFC is configured to be part of FW_CONFIG, add it at the most significant
700 * 32 bits.
701 */
702 if (CONFIG(EC_GOOGLE_CHROMEEC_INCLUDE_SSFC_IN_FW_CONFIG)) {
703 uint32_t ssfc;
704
Kangheui Won082be102021-04-09 15:37:15 +1000705 if (!google_chromeec_cbi_get_ssfc(&ssfc))
706 *fw_config |= (uint64_t)ssfc << 32;
Karthikeyan Ramasubramanian86728842021-02-25 00:29:14 -0700707 }
Tim Wawrzynczak24b4af62020-10-01 15:41:31 -0600708 return 0;
Jett Rink8db8a612020-01-14 11:41:47 -0700709}
710
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800711int google_chromeec_cbi_get_oem_id(uint32_t *id)
712{
Daisuke Nojirif984a052018-02-15 12:38:15 -0800713 return cbi_get_uint32(id, CBI_TAG_OEM_ID);
Daisuke Nojiri07f9748f2018-02-01 07:46:02 -0800714}
715
Aaron Durbin53525772020-04-13 22:24:09 -0600716int google_chromeec_cbi_get_board_version(uint32_t *version)
717{
718 return cbi_get_uint32(version, CBI_TAG_BOARD_VERSION);
719}
720
Marco Chen525cc462020-12-11 14:29:23 +0800721int google_chromeec_cbi_get_ssfc(uint32_t *ssfc)
722{
723 return cbi_get_uint32(ssfc, CBI_TAG_SSFC);
724}
725
Wisley Chenc1efec72018-11-06 09:28:23 +0800726static int cbi_get_string(char *buf, size_t bufsize, uint32_t tag)
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600727{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600728 struct ec_params_get_cbi params = {
Wisley Chenc1efec72018-11-06 09:28:23 +0800729 .tag = tag,
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600730 };
731 struct chromeec_command cmd = {
732 .cmd_code = EC_CMD_GET_CROS_BOARD_INFO,
733 .cmd_version = 0,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600734 .cmd_data_in = &params,
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600735 .cmd_data_out = buf,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600736 .cmd_size_in = sizeof(params),
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600737 .cmd_size_out = bufsize,
738 };
739 int rv;
740
741 rv = google_chromeec_command(&cmd);
YH Lin40f65422019-02-26 09:56:06 -0800742 if (rv != 0)
Aaron Durbinb388c0e2018-08-07 12:24:21 -0600743 return rv;
744
745 /* Ensure NUL termination. */
746 buf[bufsize - 1] = '\0';
747
748 return 0;
749}
750
Wisley Chenc1efec72018-11-06 09:28:23 +0800751int google_chromeec_cbi_get_dram_part_num(char *buf, size_t bufsize)
752{
753 return cbi_get_string(buf, bufsize, CBI_TAG_DRAM_PART_NUM);
754}
755
756int google_chromeec_cbi_get_oem_name(char *buf, size_t bufsize)
757{
758 return cbi_get_string(buf, bufsize, CBI_TAG_OEM_NAME);
759}
760
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600761int google_chromeec_get_board_version(uint32_t *version)
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700762{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600763 struct ec_response_board_version resp;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700764
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700765 if (ec_cmd_get_board_version(PLAT_EC, &resp))
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600766 return -1;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700767
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600768 *version = resp.board_version;
Karthikeyan Ramasubramanianc80ff842018-09-17 16:19:34 -0600769 return 0;
Shawn Nematbakhshd0a6a382013-07-08 14:18:01 -0700770}
Stefan Reinaueraaaf6892013-08-29 15:57:11 -0700771
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600772uint32_t google_chromeec_get_sku_id(void)
Patrick Georgi69206d92017-07-31 14:20:07 +0200773{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600774 struct ec_sku_id_info resp;
Patrick Georgi69206d92017-07-31 14:20:07 +0200775
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700776 if (ec_cmd_get_sku_id(PLAT_EC, &resp) != 0)
Patrick Georgi69206d92017-07-31 14:20:07 +0200777 return 0;
778
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600779 return resp.sku_id;
Patrick Georgi69206d92017-07-31 14:20:07 +0200780}
781
Caveh Jalali0bab8ed2022-11-02 20:34:43 -0700782static bool google_chromeec_get_uptime_info(
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600783 struct ec_response_uptime_info *resp)
You-Cheng Syu85bb8742019-03-12 13:02:18 +0800784{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700785 return ec_cmd_get_uptime_info(PLAT_EC, resp) == 0;
You-Cheng Syu85bb8742019-03-12 13:02:18 +0800786}
787
788bool google_chromeec_get_ap_watchdog_flag(void)
789{
Yu-Ping Wu8a82ea92021-01-05 17:05:40 +0800790 int i;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600791 struct ec_response_uptime_info resp;
Yu-Ping Wu8a82ea92021-01-05 17:05:40 +0800792
Caveh Jalali0bab8ed2022-11-02 20:34:43 -0700793 if (!google_chromeec_get_uptime_info(&resp))
Yu-Ping Wu8a82ea92021-01-05 17:05:40 +0800794 return false;
795
796 if (resp.ec_reset_flags & EC_RESET_FLAG_AP_WATCHDOG)
797 return true;
798
799 /* Find the last valid entry */
800 for (i = ARRAY_SIZE(resp.recent_ap_reset) - 1; i >= 0; i--) {
801 if (resp.recent_ap_reset[i].reset_time_ms == 0)
802 continue;
803 return (resp.recent_ap_reset[i].reset_cause ==
804 CHIPSET_RESET_AP_WATCHDOG);
805 }
806
807 return false;
You-Cheng Syu85bb8742019-03-12 13:02:18 +0800808}
809
Gabe Black9f96aa62013-06-28 14:24:33 -0700810int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
811 uint8_t *buffer, int len, int is_read)
812{
813 union {
814 struct ec_params_i2c_passthru p;
815 uint8_t outbuf[EC_HOST_PARAM_SIZE];
816 } params;
817 union {
818 struct ec_response_i2c_passthru r;
819 uint8_t inbuf[EC_HOST_PARAM_SIZE];
820 } response;
821 struct ec_params_i2c_passthru *p = &params.p;
822 struct ec_response_i2c_passthru *r = &response.r;
823 struct ec_params_i2c_passthru_msg *msg = p->msg;
824 struct chromeec_command cmd;
825 uint8_t *pdata;
826 int read_len, write_len;
827 int size;
828 int rv;
829
830 p->port = 0;
831
832 if (alen != 1) {
833 printk(BIOS_ERR, "Unsupported address length %d\n", alen);
834 return -1;
835 }
836 if (is_read) {
837 read_len = len;
838 write_len = alen;
839 p->num_msgs = 2;
840 } else {
841 read_len = 0;
842 write_len = alen + len;
843 p->num_msgs = 1;
844 }
845
846 size = sizeof(*p) + p->num_msgs * sizeof(*msg);
847 if (size + write_len > sizeof(params)) {
848 printk(BIOS_ERR, "Params too large for buffer\n");
849 return -1;
850 }
851 if (sizeof(*r) + read_len > sizeof(response)) {
852 printk(BIOS_ERR, "Read length too big for buffer\n");
853 return -1;
854 }
855
856 /* Create a message to write the register address and optional data */
857 pdata = (uint8_t *)p + size;
858 msg->addr_flags = chip;
859 msg->len = write_len;
860 pdata[0] = addr;
861 if (!is_read)
862 memcpy(pdata + 1, buffer, len);
863 msg++;
864
865 if (read_len) {
866 msg->addr_flags = chip | EC_I2C_FLAG_READ;
867 msg->len = read_len;
868 }
869
870 cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
871 cmd.cmd_version = 0;
872 cmd.cmd_data_in = p;
873 cmd.cmd_size_in = size + write_len;
874 cmd.cmd_data_out = r;
875 cmd.cmd_size_out = sizeof(*r) + read_len;
Duncan Lauriefc0f5172014-09-18 12:54:02 -0700876 cmd.cmd_dev_index = 0;
Gabe Black9f96aa62013-06-28 14:24:33 -0700877 rv = google_chromeec_command(&cmd);
878 if (rv != 0)
879 return rv;
880
881 /* Parse response */
882 if (r->i2c_status & EC_I2C_STATUS_ERROR) {
883 printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
884 r->i2c_status);
885 return -1;
886 }
887
888 if (cmd.cmd_size_out < sizeof(*r) + read_len) {
889 printk(BIOS_ERR, "Truncated read response\n");
890 return -1;
891 }
892
893 if (read_len)
894 memcpy(buffer, r->data, read_len);
895
896 return 0;
897}
898
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800899int google_chromeec_set_sci_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800900{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800901 printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530902 return google_chromeec_set_mask(EC_HOST_EVENT_SCI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800903}
904
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800905int google_chromeec_set_smi_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800906{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800907 printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530908 return google_chromeec_set_mask(EC_HOST_EVENT_SMI_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800909}
910
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800911int google_chromeec_set_wake_mask(uint64_t mask)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800912{
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800913 printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
Jenny TC1dfc2c32017-12-14 14:24:39 +0530914 return google_chromeec_set_mask
915 (EC_HOST_EVENT_ACTIVE_WAKE_MASK, mask);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800916}
917
Furquan Shaikh8788fd62017-11-20 20:28:18 -0800918uint64_t google_chromeec_get_wake_mask(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800919{
Jenny TC1dfc2c32017-12-14 14:24:39 +0530920 return google_chromeec_get_mask(EC_HOST_EVENT_ACTIVE_WAKE_MASK);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800921}
922
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600923int google_chromeec_set_usb_charge_mode(uint8_t port_id, enum usb_charge_mode mode)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800924{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700925 const struct ec_params_usb_charge_set_mode params = {
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800926 .usb_port_id = port_id,
927 .mode = mode,
928 };
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800929
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700930 return ec_cmd_usb_charge_set_mode(PLAT_EC, &params);
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800931}
932
Gaggery Tsai52f18df2020-03-25 11:34:25 -0700933/* Get charger voltage and current. Also returns type of charger */
Shelley Chenebd53302017-09-29 14:15:11 -0700934int google_chromeec_get_usb_pd_power_info(enum usb_chg_type *type,
Gaggery Tsai52f18df2020-03-25 11:34:25 -0700935 uint16_t *current_max, uint16_t *voltage_max)
Shelley Chenebd53302017-09-29 14:15:11 -0700936{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700937 const struct ec_params_usb_pd_power_info params = {
Shelley Chenebd53302017-09-29 14:15:11 -0700938 .port = PD_POWER_CHARGING_PORT,
939 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600940 struct ec_response_usb_pd_power_info resp = {};
Shelley Chenebd53302017-09-29 14:15:11 -0700941 struct usb_chg_measures m;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600942 int rv;
943
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700944 rv = ec_cmd_usb_pd_power_info(PLAT_EC, &params, &resp);
Shelley Chenebd53302017-09-29 14:15:11 -0700945 if (rv != 0)
946 return rv;
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600947
Shelley Chenebd53302017-09-29 14:15:11 -0700948 /* values are given in milliAmps and milliVolts */
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600949 *type = resp.type;
950 m = resp.meas;
Gaggery Tsai52f18df2020-03-25 11:34:25 -0700951 *voltage_max = m.voltage_max;
952 *current_max = m.current_max;
Shelley Chenebd53302017-09-29 14:15:11 -0700953 return 0;
954}
955
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600956int google_chromeec_override_dedicated_charger_limit(uint16_t current_lim,
957 uint16_t voltage_lim)
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800958{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700959 const struct ec_params_dedicated_charger_limit params = {
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800960 .current_lim = current_lim,
961 .voltage_lim = voltage_lim,
962 };
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800963
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700964 return ec_cmd_override_dedicated_charger_limit(PLAT_EC, &params);
Daisuke Nojiri93fd8fa2017-11-28 14:11:30 -0800965}
966
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600967int google_chromeec_set_usb_pd_role(uint8_t port, enum usb_pd_control_role role)
Julius Wernerea79d2b2016-11-21 20:14:07 -0800968{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700969 const struct ec_params_usb_pd_control params = {
Julius Wernerea79d2b2016-11-21 20:14:07 -0800970 .port = port,
971 .role = role,
972 .mux = USB_PD_CTRL_MUX_NO_CHANGE,
973 .swap = USB_PD_CTRL_SWAP_NONE,
974 };
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600975 struct ec_response_usb_pd_control resp;
Julius Wernerea79d2b2016-11-21 20:14:07 -0800976
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700977 return ec_cmd_usb_pd_control(PLAT_EC, &params, &resp);
Julius Wernerea79d2b2016-11-21 20:14:07 -0800978}
979
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600980int google_chromeec_hello(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800981{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700982 const struct ec_params_hello params = {
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600983 .in_data = 0x10203040,
984 };
985 struct ec_response_hello resp = {};
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600986
Caveh Jalalibeaa8f892022-11-01 01:28:31 -0700987 int rv = ec_cmd_hello(PLAT_EC, &params, &resp);
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600988 if (rv)
989 return -1;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -0600990
991 if (resp.out_data != (params.in_data + 0x01020304))
992 return -1;
993
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -0600994 return 0;
Stefan Reinauerd6682e82013-02-21 15:39:35 -0800995}
996
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -0600997/*
998 * Convert a reset cause ID to human-readable string, providing total coverage
999 * of the 'cause' space. The returned string points to static storage and must
1000 * not be free()ed.
1001 */
1002static const char *reset_cause_to_str(uint16_t cause)
1003{
1004 /* See also ChromiumOS EC include/chipset.h for details. */
1005 static const char * const reset_causes[] = {
1006 "(reset unknown)",
1007 "reset: board custom",
1008 "reset: ap hang detected",
1009 "reset: console command",
1010 "reset: keyboard sysreset",
1011 "reset: keyboard warm reboot",
1012 "reset: debug warm reboot",
1013 "reset: at AP's request",
1014 "reset: during EC initialization",
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001015 "reset: AP watchdog",
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001016 };
1017
1018 static const size_t shutdown_cause_begin = 1 << 15;
1019 static const char * const shutdown_causes[] = {
1020 "shutdown: power failure",
1021 "shutdown: during EC initialization",
1022 "shutdown: board custom",
1023 "shutdown: battery voltage startup inhibit",
1024 "shutdown: power wait asserted",
1025 "shutdown: critical battery",
1026 "shutdown: by console command",
1027 "shutdown: entering G3",
1028 "shutdown: thermal",
1029 "shutdown: power button",
1030 };
1031
1032 if (cause < ARRAY_SIZE(reset_causes))
1033 return reset_causes[cause];
1034
1035 if (cause < shutdown_cause_begin)
1036 return "(reset unknown)";
1037
1038 if (cause < shutdown_cause_begin + ARRAY_SIZE(shutdown_causes))
1039 return shutdown_causes[cause - shutdown_cause_begin];
1040
1041 return "(shutdown unknown)";
1042}
1043
1044/*
1045 * Copy the EC's information about resets of the AP and its own uptime for
1046 * debugging purposes.
1047 */
1048static void google_chromeec_log_uptimeinfo(void)
1049{
You-Cheng Syu8d6ea6a2019-03-13 21:37:23 +08001050 /* See also ec_commands.h EC_RESET_FLAG_* for details. */
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001051 static const char * const reset_flag_strings[] = {
1052 "other",
1053 "reset-pin",
1054 "brownout",
1055 "power-on",
1056 "watchdog",
1057 "soft",
1058 "hibernate",
1059 "rtc-alarm",
1060 "wake-pin",
1061 "low-battery",
1062 "sysjump",
1063 "hard",
1064 "ap-off",
1065 "preserved",
1066 "usb-resume",
1067 "rdd",
1068 "rbox",
You-Cheng Syu85bb8742019-03-12 13:02:18 +08001069 "security",
1070 "ap-watchdog",
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001071 };
1072 struct ec_response_uptime_info cmd_resp;
1073 int i, flag, flag_count;
1074
Caveh Jalali0bab8ed2022-11-02 20:34:43 -07001075 if (!google_chromeec_get_uptime_info(&cmd_resp)) {
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001076 /*
1077 * Deliberately say nothing for EC's that don't support this
1078 * command
1079 */
1080 return;
1081 }
1082
1083 printk(BIOS_DEBUG, "Google Chrome EC uptime: %d.%03d seconds\n",
1084 cmd_resp.time_since_ec_boot_ms / MSECS_PER_SEC,
1085 cmd_resp.time_since_ec_boot_ms % MSECS_PER_SEC);
1086
1087 printk(BIOS_DEBUG, "Google Chrome AP resets since EC boot: %d\n",
1088 cmd_resp.ap_resets_since_ec_boot);
1089
1090 printk(BIOS_DEBUG, "Google Chrome most recent AP reset causes:\n");
1091 for (i = 0; i != ARRAY_SIZE(cmd_resp.recent_ap_reset); ++i) {
1092 if (cmd_resp.recent_ap_reset[i].reset_time_ms == 0)
1093 continue;
1094
1095 printk(BIOS_DEBUG, "\t%d.%03d: %d %s\n",
1096 cmd_resp.recent_ap_reset[i].reset_time_ms /
1097 MSECS_PER_SEC,
1098 cmd_resp.recent_ap_reset[i].reset_time_ms %
1099 MSECS_PER_SEC,
1100 cmd_resp.recent_ap_reset[i].reset_cause,
1101 reset_cause_to_str(
1102 cmd_resp.recent_ap_reset[i].reset_cause));
1103 }
1104
1105 printk(BIOS_DEBUG, "Google Chrome EC reset flags at last EC boot: ");
1106 flag_count = 0;
1107 for (flag = 0; flag != ARRAY_SIZE(reset_flag_strings); ++flag) {
1108 if ((cmd_resp.ec_reset_flags & (1 << flag)) != 0) {
1109 if (flag_count)
1110 printk(BIOS_DEBUG, " | ");
Greg Vae47a6f2019-10-04 02:49:20 +03001111 printk(BIOS_DEBUG, "%s", reset_flag_strings[flag]);
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001112 flag_count++;
1113 }
1114 }
1115 printk(BIOS_DEBUG, "\n");
1116}
1117
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001118/* Cache and retrieve the EC image type (ro or rw) */
Furquan Shaikha6cf8d62020-04-07 22:22:22 -07001119enum ec_image google_chromeec_get_current_image(void)
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001120{
Kyösti Mälkkifcbbb912020-04-20 10:21:39 +03001121 static enum ec_image ec_image_type = EC_IMAGE_UNKNOWN;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001122
1123 if (ec_image_type != EC_IMAGE_UNKNOWN)
1124 return ec_image_type;
1125
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001126 struct ec_response_get_version resp = {};
Caveh Jalali675de752022-11-02 20:48:51 -07001127 int rv;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001128
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001129 rv = ec_cmd_get_version(PLAT_EC, &resp);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001130
Caveh Jalali675de752022-11-02 20:48:51 -07001131 if (rv != 0) {
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001132 printk(BIOS_DEBUG,
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001133 "Google Chrome EC: version command failed!\n");
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001134 } else {
1135 printk(BIOS_DEBUG, "Google Chrome EC: version:\n");
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001136 printk(BIOS_DEBUG, " ro: %s\n", resp.version_string_ro);
1137 printk(BIOS_DEBUG, " rw: %s\n", resp.version_string_rw);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001138 printk(BIOS_DEBUG, " running image: %d\n",
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001139 resp.current_image);
1140 ec_image_type = resp.current_image;
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001141 }
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001142
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001143 /* Will still be UNKNOWN if command failed */
1144 return ec_image_type;
1145}
1146
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001147int google_chromeec_get_num_pd_ports(unsigned int *num_ports)
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001148{
Caveh Jalali21552ae2022-11-02 18:59:36 -07001149 struct ec_response_usb_pd_ports resp = {};
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001150 int rv;
1151
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001152 rv = ec_cmd_usb_pd_ports(PLAT_EC, &resp);
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001153 if (rv)
1154 return rv;
1155
Caveh Jalali21552ae2022-11-02 18:59:36 -07001156 *num_ports = resp.num_ports;
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001157 return 0;
1158}
1159
1160int google_chromeec_get_pd_port_caps(int port,
1161 struct usb_pd_port_caps *port_caps)
1162{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001163 const struct ec_params_get_pd_port_caps params = {
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001164 .port = port,
1165 };
1166 struct ec_response_get_pd_port_caps resp = {};
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001167 int rv;
1168
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001169 rv = ec_cmd_get_pd_port_caps(PLAT_EC, &params, &resp);
Tim Wawrzynczake6078292020-01-22 15:22:18 -07001170 if (rv)
1171 return rv;
1172
1173 port_caps->power_role_cap = resp.pd_power_role_cap;
1174 port_caps->try_power_role_cap = resp.pd_try_power_role_cap;
1175 port_caps->data_role_cap = resp.pd_data_role_cap;
1176 port_caps->port_location = resp.pd_port_location;
1177
1178 return 0;
1179}
1180
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001181void google_chromeec_init(void)
1182{
Jonathan Brandmeyerbd21f28442018-07-23 16:44:51 -06001183 google_chromeec_log_uptimeinfo();
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001184}
1185
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001186int google_ec_running_ro(void)
1187{
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001188 return (google_chromeec_get_current_image() == EC_IMAGE_RO);
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001189}
Stefan Reinauerd6682e82013-02-21 15:39:35 -08001190
Derek Huang796ea822021-09-29 22:05:04 +08001191/* Returns data role and type of device connected */
1192static int google_chromeec_usb_pd_get_info(int port, bool *ufp, bool *dbg_acc,
Derek Huangf1f9b3d2021-09-29 16:39:01 +08001193 bool *active_cable, uint8_t *dp_mode)
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001194{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001195 const struct ec_params_usb_pd_control pd_control = {
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001196 .port = port,
1197 .role = USB_PD_CTRL_ROLE_NO_CHANGE,
1198 .mux = USB_PD_CTRL_ROLE_NO_CHANGE,
1199 .swap = USB_PD_CTRL_SWAP_NONE,
1200 };
1201 struct ec_response_usb_pd_control_v2 resp = {};
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001202
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001203 if (ec_cmd_usb_pd_control_v2(PLAT_EC, &pd_control, &resp) < 0)
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001204 return -1;
1205
Dtrain Hsubb20e422022-08-29 15:43:01 +08001206 *ufp = !(resp.role & PD_CTRL_RESP_ROLE_DATA);
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001207 *dbg_acc = (resp.cc_state == PD_CC_DFP_DEBUG_ACC);
Derek Huangf1f9b3d2021-09-29 16:39:01 +08001208 *active_cable = !!(resp.control_flags & USB_PD_CTRL_ACTIVE_CABLE);
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001209 *dp_mode = resp.dp_mode;
1210
1211 return 0;
1212}
1213
Derek Huangc0bd1232021-08-25 17:19:39 +08001214int google_chromeec_typec_control_enter_dp_mode(int port)
1215{
Kapil Porwalc2c58012023-07-10 11:27:17 +00001216 int ret;
1217 struct usbc_mux_info mux_info;
1218
Derek Huangc0bd1232021-08-25 17:19:39 +08001219 if (!google_chromeec_check_feature(EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY))
1220 return 0;
1221
Kapil Porwalc2c58012023-07-10 11:27:17 +00001222 ret = google_chromeec_get_usbc_mux_info(port, &mux_info);
1223 if ((ret < 0) || (!mux_info.usb))
1224 return -1;
1225
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001226 const struct ec_params_typec_control typec_control = {
Derek Huangc0bd1232021-08-25 17:19:39 +08001227 .port = port,
1228 .command = TYPEC_CONTROL_COMMAND_ENTER_MODE,
1229 .mode_to_enter = TYPEC_MODE_DP,
1230 };
1231
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001232 if (ec_cmd_typec_control(PLAT_EC, &typec_control) < 0)
Derek Huangc0bd1232021-08-25 17:19:39 +08001233 return -1;
1234
1235 return 0;
1236}
1237
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001238/**
1239 * Check for the current mux state in EC. Flags representing the mux state found
1240 * in ec_commands.h
1241 */
1242int google_chromeec_usb_get_pd_mux_info(int port, uint8_t *flags)
1243{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001244 const struct ec_params_usb_pd_mux_info req_mux = {
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001245 .port = port,
1246 };
1247 struct ec_response_usb_pd_mux_info resp_mux = {};
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001248
1249 if (port < 0)
1250 return -1;
1251
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001252 if (ec_cmd_usb_pd_mux_info(PLAT_EC, &req_mux, &resp_mux) < 0)
Divya Sasidharan49d74de2019-10-22 13:41:15 -07001253 return -1;
1254
1255 *flags = resp_mux.flags;
1256 return 0;
1257}
1258
Derek Huang63ffc1a2021-09-29 21:59:45 +08001259/*
1260 * Obtain any USB-C mux data needed for the specified port
1261 * in: physical port number of the type-c port
1262 * out: struct usbc_mux_info mux_info stores USB-C mux data
1263 * Return: 0 on success, -1 on error
1264*/
1265int google_chromeec_get_usbc_mux_info(int port, struct usbc_mux_info *mux_info)
1266{
1267 uint8_t mux_flags;
1268 uint8_t dp_pin_mode;
1269 bool ufp, dbg_acc, active_cable;
1270
1271 if (google_chromeec_usb_get_pd_mux_info(port, &mux_flags) < 0) {
1272 printk(BIOS_ERR, "Port C%d: get_pd_mux_info failed\n", port);
1273 return -1;
1274 }
1275
1276 if (google_chromeec_usb_pd_get_info(port, &ufp, &dbg_acc,
1277 &active_cable, &dp_pin_mode) < 0) {
1278 printk(BIOS_ERR, "Port C%d: pd_control failed\n", port);
1279 return -1;
1280 }
1281
1282 mux_info->usb = !!(mux_flags & USB_PD_MUX_USB_ENABLED);
1283 mux_info->dp = !!(mux_flags & USB_PD_MUX_DP_ENABLED);
1284 mux_info->polarity = !!(mux_flags & USB_PD_MUX_POLARITY_INVERTED);
1285 mux_info->hpd_irq = !!(mux_flags & USB_PD_MUX_HPD_IRQ);
1286 mux_info->hpd_lvl = !!(mux_flags & USB_PD_MUX_HPD_LVL);
1287 mux_info->ufp = !!ufp;
1288 mux_info->dbg_acc = !!dbg_acc;
1289 mux_info->cable = !!active_cable;
1290 mux_info->dp_pin_mode = dp_pin_mode;
1291
1292 return 0;
1293}
1294
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001295/**
1296 * Check if EC/TCPM is in an alternate mode or not.
1297 *
1298 * @param svid SVID of the alternate mode to check
Derek Huangc0f005a2021-09-29 17:38:31 +08001299 * @return 0: Not in the mode. -1: Error.
1300 * >=1: bitmask of the ports that are in the mode.
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001301 */
Derek Huangc0f005a2021-09-29 17:38:31 +08001302static int google_chromeec_pd_get_amode(uint16_t svid)
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001303{
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001304 struct ec_response_usb_pd_ports resp;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001305 int i;
Derek Huangc0f005a2021-09-29 17:38:31 +08001306 int ret = 0;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001307
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001308 if (ec_cmd_usb_pd_ports(PLAT_EC, &resp) < 0)
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001309 return -1;
1310
Tim Wawrzynczakb5c345a2019-10-24 10:12:01 -06001311 for (i = 0; i < resp.num_ports; i++) {
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001312 struct chromeec_command cmd = { };
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001313 struct ec_params_usb_pd_get_mode_request params;
1314 struct ec_params_usb_pd_get_mode_response resp2;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001315 int svid_idx = 0;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001316
1317 do {
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001318 /* Reset cmd in each iteration in case
1319 google_chromeec_command changes it. */
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001320 params.port = i;
1321 params.svid_idx = svid_idx;
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001322 cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE;
1323 cmd.cmd_version = 0;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001324 cmd.cmd_data_in = &params;
1325 cmd.cmd_size_in = sizeof(params);
1326 cmd.cmd_data_out = &resp2;
1327 cmd.cmd_size_out = sizeof(resp2);
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001328 cmd.cmd_dev_index = 0;
1329
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001330 if (google_chromeec_command(&cmd) < 0)
1331 return -1;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001332 if (resp2.svid == svid)
Derek Huangc0f005a2021-09-29 17:38:31 +08001333 ret |= BIT(i);
Daisuke Nojiriccfa18f2018-04-26 12:59:58 -07001334 svid_idx++;
Tim Wawrzynczak1966b5c802019-10-21 13:09:09 -06001335 } while (resp2.svid);
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001336 }
1337
Derek Huangc0f005a2021-09-29 17:38:31 +08001338 return ret;
Daisuke Nojiri476c2c52018-01-26 17:36:44 -08001339}
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001340
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001341#define USB_SID_DISPLAYPORT 0xff01
1342
Daisuke Nojirid182b632018-02-16 17:50:06 -08001343/**
1344 * Wait for DisplayPort to be ready
1345 *
Derek Huangc0f005a2021-09-29 17:38:31 +08001346 * @param timeout_ms Wait aborts after <timeout_ms> ms.
1347 * @return -1: Error. 0: Timeout.
1348 * >=1: Bitmask of the ports that DP device is connected
Daisuke Nojirid182b632018-02-16 17:50:06 -08001349 */
Derek Huangc0f005a2021-09-29 17:38:31 +08001350int google_chromeec_wait_for_displayport(long timeout_ms)
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001351{
1352 struct stopwatch sw;
Derek Huangc0f005a2021-09-29 17:38:31 +08001353 int ret = 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001354
Kapil Porwal9a127bf2023-07-10 11:29:40 +00001355 if (google_chromeec_check_feature(EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY)) {
1356 printk(BIOS_INFO, "AP Mode Entry enabled, skip waiting for DisplayPort connection\n");
1357 return -1;
1358 }
1359
Daisuke Nojirid182b632018-02-16 17:50:06 -08001360 printk(BIOS_INFO, "Waiting for DisplayPort\n");
Derek Huangc0f005a2021-09-29 17:38:31 +08001361 stopwatch_init_msecs_expire(&sw, timeout_ms);
1362 while (1) {
1363 ret = google_chromeec_pd_get_amode(USB_SID_DISPLAYPORT);
1364 if (ret > 0)
1365 break;
1366
1367 if (ret < 0) {
1368 printk(BIOS_ERR, "Can't get alternate mode!\n");
1369 return ret;
1370 }
1371
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001372 if (stopwatch_expired(&sw)) {
1373 printk(BIOS_WARNING,
Daisuke Nojirid182b632018-02-16 17:50:06 -08001374 "DisplayPort not ready after %ldms. Abort.\n",
Derek Huangc0f005a2021-09-29 17:38:31 +08001375 timeout_ms);
Daisuke Nojirid182b632018-02-16 17:50:06 -08001376 return 0;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001377 }
1378 mdelay(200);
1379 }
Rob Barnesd522f382022-09-12 06:31:47 -06001380 printk(BIOS_INFO, "DisplayPort ready after %lld ms\n",
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001381 stopwatch_duration_msecs(&sw));
Daisuke Nojirid182b632018-02-16 17:50:06 -08001382
Derek Huangc0f005a2021-09-29 17:38:31 +08001383 return ret;
Daisuke Nojiriebb86be2018-01-26 17:36:44 -08001384}
Rajat Jain89eef552020-04-10 15:48:49 -07001385
Kapil Porwal2ba4b1b2023-07-10 11:37:26 +00001386/**
1387 * Check for given flag in PD mux info for a port.
1388 *
1389 * @param port Type-C port number
1390 * flag Flag to check
1391 * @return 1: Flag is set. 0: Flag is not set.
1392 */
1393static int google_chromeec_check_mux_flag(int port, uint8_t flag)
Derek Huangc0bd1232021-08-25 17:19:39 +08001394{
Kapil Porwal2ba4b1b2023-07-10 11:37:26 +00001395 uint8_t mux_flags = 0;
1396 google_chromeec_usb_get_pd_mux_info(port, &mux_flags);
1397 if ((mux_flags & flag) == flag)
1398 return 1;
1399 return 0;
1400}
1401
1402int google_chromeec_wait_for_dp_mode_entry(int port, long timeout_ms)
1403{
Derek Huangc0bd1232021-08-25 17:19:39 +08001404 struct stopwatch sw;
1405
Kapil Porwal1d854642023-07-10 11:31:59 +00001406 if (!google_chromeec_check_feature(EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY)) {
Kapil Porwal2ba4b1b2023-07-10 11:37:26 +00001407 if (!google_chromeec_check_mux_flag(port, USB_PD_MUX_DP_ENABLED)) {
1408 printk(BIOS_WARNING, "DP mode entry is not ready. Abort.\n");
Kapil Porwal1d854642023-07-10 11:31:59 +00001409 return -1;
1410 }
1411
1412 return 0;
1413 }
1414
Derek Huangc0bd1232021-08-25 17:19:39 +08001415 stopwatch_init_msecs_expire(&sw, timeout_ms);
Kapil Porwal2ba4b1b2023-07-10 11:37:26 +00001416 while (!google_chromeec_check_mux_flag(port, USB_PD_MUX_DP_ENABLED)) {
1417 if (stopwatch_expired(&sw)) {
1418 printk(BIOS_WARNING, "DP not ready after %ldms. Abort.\n", timeout_ms);
1419 return -1;
1420 }
1421 mdelay(100);
1422 }
1423 printk(BIOS_INFO, "DP ready after %lld ms\n", stopwatch_duration_msecs(&sw));
1424
1425 return 0;
1426}
1427
1428int google_chromeec_wait_for_hpd(int port, long timeout_ms)
1429{
1430 struct stopwatch sw;
1431
1432 if (!google_chromeec_check_feature(EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY)) {
1433 if (!google_chromeec_check_mux_flag(port, USB_PD_MUX_HPD_LVL)) {
1434 printk(BIOS_WARNING, "HPD not ready. Abort.\n");
1435 return -1;
1436 }
1437
1438 return 0;
1439 }
1440
1441 stopwatch_init_msecs_expire(&sw, timeout_ms);
1442 while (!google_chromeec_check_mux_flag(port, USB_PD_MUX_HPD_LVL)) {
Derek Huangc0bd1232021-08-25 17:19:39 +08001443 if (stopwatch_expired(&sw)) {
1444 printk(BIOS_WARNING, "HPD not ready after %ldms. Abort.\n", timeout_ms);
1445 return -1;
1446 }
1447 mdelay(100);
Kapil Porwal2ba4b1b2023-07-10 11:37:26 +00001448 }
Rob Barnesd522f382022-09-12 06:31:47 -06001449 printk(BIOS_INFO, "HPD ready after %lld ms\n", stopwatch_duration_msecs(&sw));
Derek Huangc0bd1232021-08-25 17:19:39 +08001450
1451 return 0;
1452}
1453
Rajat Jain89eef552020-04-10 15:48:49 -07001454int google_chromeec_get_keybd_config(struct ec_response_keybd_config *keybd)
1455{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001456 if (ec_cmd_get_keybd_config(PLAT_EC, keybd))
Rajat Jain89eef552020-04-10 15:48:49 -07001457 return -1;
Rajat Jain89eef552020-04-10 15:48:49 -07001458 return 0;
1459}
Karthikeyan Ramasubramanianc96d12e2020-08-04 16:50:02 -06001460
1461int google_chromeec_ap_reset(void)
1462{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001463 if (ec_cmd_ap_reset(NULL))
Karthikeyan Ramasubramanianc96d12e2020-08-04 16:50:02 -06001464 return -1;
1465
1466 return 0;
1467}
Yidi Lin79a812e2020-09-21 20:25:54 +08001468
Yidi Lin99e6dd92020-10-23 16:02:59 +08001469int google_chromeec_regulator_enable(uint32_t index, uint8_t enable)
1470{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001471 const struct ec_params_regulator_enable params = {
Yidi Lin99e6dd92020-10-23 16:02:59 +08001472 .index = index,
1473 .enable = enable,
1474 };
Yidi Lin99e6dd92020-10-23 16:02:59 +08001475
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001476 if (ec_cmd_regulator_enable(PLAT_EC, &params))
Yidi Lin99e6dd92020-10-23 16:02:59 +08001477 return -1;
1478
1479 return 0;
1480}
1481
1482int google_chromeec_regulator_is_enabled(uint32_t index, uint8_t *enabled)
1483{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001484 const struct ec_params_regulator_is_enabled params = {
Yidi Lin99e6dd92020-10-23 16:02:59 +08001485 .index = index,
1486 };
1487 struct ec_response_regulator_is_enabled resp = {};
Yidi Lin99e6dd92020-10-23 16:02:59 +08001488
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001489 if (ec_cmd_regulator_is_enabled(PLAT_EC, &params, &resp))
Yidi Lin99e6dd92020-10-23 16:02:59 +08001490 return -1;
1491
1492 *enabled = resp.enabled;
1493
1494 return 0;
1495}
1496
Yidi Lin79a812e2020-09-21 20:25:54 +08001497int google_chromeec_regulator_set_voltage(uint32_t index, uint32_t min_mv,
1498 uint32_t max_mv)
1499{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001500 const struct ec_params_regulator_set_voltage params = {
Yidi Lin79a812e2020-09-21 20:25:54 +08001501 .index = index,
1502 .min_mv = min_mv,
1503 .max_mv = max_mv,
1504 };
Yidi Lin79a812e2020-09-21 20:25:54 +08001505
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001506 if (ec_cmd_regulator_set_voltage(PLAT_EC, &params))
Yidi Lin79a812e2020-09-21 20:25:54 +08001507 return -1;
1508
1509 return 0;
1510}
1511
1512int google_chromeec_regulator_get_voltage(uint32_t index, uint32_t *voltage_mv)
1513{
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001514 const struct ec_params_regulator_get_voltage params = {
Yidi Lin79a812e2020-09-21 20:25:54 +08001515 .index = index,
1516 };
1517 struct ec_response_regulator_get_voltage resp = {};
Yidi Lin79a812e2020-09-21 20:25:54 +08001518
Caveh Jalalibeaa8f892022-11-01 01:28:31 -07001519 if (ec_cmd_regulator_get_voltage(PLAT_EC, &params, &resp))
Yidi Lin79a812e2020-09-21 20:25:54 +08001520 return -1;
1521
1522 *voltage_mv = resp.voltage_mv;
1523 return 0;
1524}
Derek Huangc6f47382023-09-01 04:17:11 +00001525
1526void google_chromeec_clear_ec_ap_idle(void)
1527{
1528 /* Send EC command to clear AP_IDLE flag */
1529 if (!google_chromeec_reboot(EC_REBOOT_NO_OP, EC_REBOOT_FLAG_CLEAR_AP_IDLE |
1530 EC_REBOOT_FLAG_ON_AP_SHUTDOWN))
1531 printk(BIOS_INFO, "Successfully clear AP_IDLE flag\n");
1532 else
1533 printk(BIOS_ERR, "Failed to clear EC AP_IDLE flag\n");
1534}
Jamie Ryu19080a72023-10-11 20:11:52 -07001535
1536bool google_chromeec_is_battery_present_and_above_critical_threshold(void)
1537{
1538 struct ec_params_battery_dynamic_info params = {
1539 .index = 0,
1540 };
1541 struct ec_response_battery_dynamic_info resp;
1542
1543 if (ec_cmd_battery_get_dynamic(PLAT_EC, &params, &resp) == 0) {
1544 /* Check if battery is present and LEVEL_CRITICAL is not set */
1545 if (resp.flags && !(resp.flags & EC_BATT_FLAG_LEVEL_CRITICAL))
1546 return true;
1547 }
1548
1549 return false;
1550}