Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2// ChromeOS EC communication protocol helper functions
3//
4// Copyright (C) 2015 Google, Inc
5
6#include <linux/mfd/cros_ec.h>
7#include <linux/delay.h>
8#include <linux/device.h>
9#include <linux/module.h>
10#include <linux/slab.h>
11#include <asm/unaligned.h>
12
13#include "cros_ec_trace.h"
14
15#define EC_COMMAND_RETRIES 50
16
17static int prepare_packet(struct cros_ec_device *ec_dev,
18 struct cros_ec_command *msg)
19{
20 struct ec_host_request *request;
21 u8 *out;
22 int i;
23 u8 csum = 0;
24
25 BUG_ON(ec_dev->proto_version != EC_HOST_REQUEST_VERSION);
26 BUG_ON(msg->outsize + sizeof(*request) > ec_dev->dout_size);
27
28 out = ec_dev->dout;
29 request = (struct ec_host_request *)out;
30 request->struct_version = EC_HOST_REQUEST_VERSION;
31 request->checksum = 0;
32 request->command = msg->command;
33 request->command_version = msg->version;
34 request->reserved = 0;
35 request->data_len = msg->outsize;
36
37 for (i = 0; i < sizeof(*request); i++)
38 csum += out[i];
39
40 /* Copy data and update checksum */
41 memcpy(out + sizeof(*request), msg->data, msg->outsize);
42 for (i = 0; i < msg->outsize; i++)
43 csum += msg->data[i];
44
45 request->checksum = -csum;
46
47 return sizeof(*request) + msg->outsize;
48}
49
50static int send_command(struct cros_ec_device *ec_dev,
51 struct cros_ec_command *msg)
52{
53 int ret;
54 int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);
55
56 trace_cros_ec_cmd(msg);
57
58 if (ec_dev->proto_version > 2)
59 xfer_fxn = ec_dev->pkt_xfer;
60 else
61 xfer_fxn = ec_dev->cmd_xfer;
62
63 if (!xfer_fxn) {
64 /*
65 * This error can happen if a communication error happened and
66 * the EC is trying to use protocol v2, on an underlying
67 * communication mechanism that does not support v2.
68 */
69 dev_err_once(ec_dev->dev,
70 "missing EC transfer API, cannot send command\n");
71 return -EIO;
72 }
73
74 ret = (*xfer_fxn)(ec_dev, msg);
75 if (msg->result == EC_RES_IN_PROGRESS) {
76 int i;
77 struct cros_ec_command *status_msg;
78 struct ec_response_get_comms_status *status;
79
80 status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status),
81 GFP_KERNEL);
82 if (!status_msg)
83 return -ENOMEM;
84
85 status_msg->version = 0;
86 status_msg->command = EC_CMD_GET_COMMS_STATUS;
87 status_msg->insize = sizeof(*status);
88 status_msg->outsize = 0;
89
90 /*
91 * Query the EC's status until it's no longer busy or
92 * we encounter an error.
93 */
94 for (i = 0; i < EC_COMMAND_RETRIES; i++) {
95 usleep_range(10000, 11000);
96
97 ret = (*xfer_fxn)(ec_dev, status_msg);
98 if (ret == -EAGAIN)
99 continue;
100 if (ret < 0)
101 break;
102
103 msg->result = status_msg->result;
104 if (status_msg->result != EC_RES_SUCCESS)
105 break;
106
107 status = (struct ec_response_get_comms_status *)
108 status_msg->data;
109 if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
110 break;
111 }
112
113 kfree(status_msg);
114 }
115
116 return ret;
117}
118
119int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
120 struct cros_ec_command *msg)
121{
122 u8 *out;
123 u8 csum;
124 int i;
125
126 if (ec_dev->proto_version > 2)
127 return prepare_packet(ec_dev, msg);
128
129 BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
130 out = ec_dev->dout;
131 out[0] = EC_CMD_VERSION0 + msg->version;
132 out[1] = msg->command;
133 out[2] = msg->outsize;
134 csum = out[0] + out[1] + out[2];
135 for (i = 0; i < msg->outsize; i++)
136 csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];
137 out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum;
138
139 return EC_MSG_TX_PROTO_BYTES + msg->outsize;
140}
141EXPORT_SYMBOL(cros_ec_prepare_tx);
142
143int cros_ec_check_result(struct cros_ec_device *ec_dev,
144 struct cros_ec_command *msg)
145{
146 switch (msg->result) {
147 case EC_RES_SUCCESS:
148 return 0;
149 case EC_RES_IN_PROGRESS:
150 dev_dbg(ec_dev->dev, "command 0x%02x in progress\n",
151 msg->command);
152 return -EAGAIN;
153 default:
154 dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n",
155 msg->command, msg->result);
156 return 0;
157 }
158}
159EXPORT_SYMBOL(cros_ec_check_result);
160
161/*
162 * cros_ec_get_host_event_wake_mask
163 *
164 * Get the mask of host events that cause wake from suspend.
165 *
166 * @ec_dev: EC device to call
167 * @msg: message structure to use
168 * @mask: result when function returns >=0.
169 *
170 * LOCKING:
171 * the caller has ec_dev->lock mutex, or the caller knows there is
172 * no other command in progress.
173 */
174static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev,
175 struct cros_ec_command *msg,
176 uint32_t *mask)
177{
178 struct ec_response_host_event_mask *r;
179 int ret;
180
181 msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK;
182 msg->version = 0;
183 msg->outsize = 0;
184 msg->insize = sizeof(*r);
185
186 ret = send_command(ec_dev, msg);
187 if (ret > 0) {
188 r = (struct ec_response_host_event_mask *)msg->data;
189 *mask = r->mask;
190 }
191
192 return ret;
193}
194
195static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
196 int devidx,
197 struct cros_ec_command *msg)
198{
199 /*
200 * Try using v3+ to query for supported protocols. If this
201 * command fails, fall back to v2. Returns the highest protocol
202 * supported by the EC.
203 * Also sets the max request/response/passthru size.
204 */
205 int ret;
206
207 if (!ec_dev->pkt_xfer)
208 return -EPROTONOSUPPORT;
209
210 memset(msg, 0, sizeof(*msg));
211 msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO;
212 msg->insize = sizeof(struct ec_response_get_protocol_info);
213
214 ret = send_command(ec_dev, msg);
215
216 if (ret < 0) {
217 dev_dbg(ec_dev->dev,
218 "failed to check for EC[%d] protocol version: %d\n",
219 devidx, ret);
220 return ret;
221 }
222
223 if (devidx > 0 && msg->result == EC_RES_INVALID_COMMAND)
224 return -ENODEV;
225 else if (msg->result != EC_RES_SUCCESS)
226 return msg->result;
227
228 return 0;
229}
230
231static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
232{
233 struct cros_ec_command *msg;
234 struct ec_params_hello *hello_params;
235 struct ec_response_hello *hello_response;
236 int ret;
237 int len = max(sizeof(*hello_params), sizeof(*hello_response));
238
239 msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
240 if (!msg)
241 return -ENOMEM;
242
243 msg->version = 0;
244 msg->command = EC_CMD_HELLO;
245 hello_params = (struct ec_params_hello *)msg->data;
246 msg->outsize = sizeof(*hello_params);
247 hello_response = (struct ec_response_hello *)msg->data;
248 msg->insize = sizeof(*hello_response);
249
250 hello_params->in_data = 0xa0b0c0d0;
251
252 ret = send_command(ec_dev, msg);
253
254 if (ret < 0) {
255 dev_dbg(ec_dev->dev,
256 "EC failed to respond to v2 hello: %d\n",
257 ret);
258 goto exit;
259 } else if (msg->result != EC_RES_SUCCESS) {
260 dev_err(ec_dev->dev,
261 "EC responded to v2 hello with error: %d\n",
262 msg->result);
263 ret = msg->result;
264 goto exit;
265 } else if (hello_response->out_data != 0xa1b2c3d4) {
266 dev_err(ec_dev->dev,
267 "EC responded to v2 hello with bad result: %u\n",
268 hello_response->out_data);
269 ret = -EBADMSG;
270 goto exit;
271 }
272
273 ret = 0;
274
275 exit:
276 kfree(msg);
277 return ret;
278}
279
280/*
281 * cros_ec_get_host_command_version_mask
282 *
283 * Get the version mask of a given command.
284 *
285 * @ec_dev: EC device to call
286 * @msg: message structure to use
287 * @cmd: command to get the version of.
288 * @mask: result when function returns 0.
289 *
290 * @return 0 on success, error code otherwise
291 *
292 * LOCKING:
293 * the caller has ec_dev->lock mutex or the caller knows there is
294 * no other command in progress.
295 */
296static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
297 u16 cmd, u32 *mask)
298{
299 struct ec_params_get_cmd_versions *pver;
300 struct ec_response_get_cmd_versions *rver;
301 struct cros_ec_command *msg;
302 int ret;
303
304 msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
305 GFP_KERNEL);
306 if (!msg)
307 return -ENOMEM;
308
309 msg->version = 0;
310 msg->command = EC_CMD_GET_CMD_VERSIONS;
311 msg->insize = sizeof(*rver);
312 msg->outsize = sizeof(*pver);
313
314 pver = (struct ec_params_get_cmd_versions *)msg->data;
315 pver->cmd = cmd;
316
317 ret = send_command(ec_dev, msg);
318 if (ret > 0) {
319 rver = (struct ec_response_get_cmd_versions *)msg->data;
320 *mask = rver->version_mask;
321 }
322
323 kfree(msg);
324
325 return ret;
326}
327
328int cros_ec_query_all(struct cros_ec_device *ec_dev)
329{
330 struct device *dev = ec_dev->dev;
331 struct cros_ec_command *proto_msg;
332 struct ec_response_get_protocol_info *proto_info;
333 u32 ver_mask = 0;
334 int ret;
335
336 proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
337 GFP_KERNEL);
338 if (!proto_msg)
339 return -ENOMEM;
340
341 /* First try sending with proto v3. */
342 ec_dev->proto_version = 3;
343 ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg);
344
345 if (ret == 0) {
346 proto_info = (struct ec_response_get_protocol_info *)
347 proto_msg->data;
348 ec_dev->max_request = proto_info->max_request_packet_size -
349 sizeof(struct ec_host_request);
350 ec_dev->max_response = proto_info->max_response_packet_size -
351 sizeof(struct ec_host_response);
352 ec_dev->proto_version =
353 min(EC_HOST_REQUEST_VERSION,
354 fls(proto_info->protocol_versions) - 1);
355 dev_dbg(ec_dev->dev,
356 "using proto v%u\n",
357 ec_dev->proto_version);
358
359 ec_dev->din_size = ec_dev->max_response +
360 sizeof(struct ec_host_response) +
361 EC_MAX_RESPONSE_OVERHEAD;
362 ec_dev->dout_size = ec_dev->max_request +
363 sizeof(struct ec_host_request) +
364 EC_MAX_REQUEST_OVERHEAD;
365
366 /*
367 * Check for PD
368 */
369 ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg);
370
371 if (ret) {
372 dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret);
373 ec_dev->max_passthru = 0;
374 } else {
375 dev_dbg(ec_dev->dev, "found PD chip\n");
376 ec_dev->max_passthru =
377 proto_info->max_request_packet_size -
378 sizeof(struct ec_host_request);
379 }
380 } else {
381 /* Try querying with a v2 hello message. */
382 ec_dev->proto_version = 2;
383 ret = cros_ec_host_command_proto_query_v2(ec_dev);
384
385 if (ret == 0) {
386 /* V2 hello succeeded. */
387 dev_dbg(ec_dev->dev, "falling back to proto v2\n");
388
389 ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;
390 ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;
391 ec_dev->max_passthru = 0;
392 ec_dev->pkt_xfer = NULL;
393 ec_dev->din_size = EC_PROTO2_MSG_BYTES;
394 ec_dev->dout_size = EC_PROTO2_MSG_BYTES;
395 } else {
396 /*
397 * It's possible for a test to occur too early when
398 * the EC isn't listening. If this happens, we'll
399 * test later when the first command is run.
400 */
401 ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN;
402 dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret);
403 goto exit;
404 }
405 }
406
407 devm_kfree(dev, ec_dev->din);
408 devm_kfree(dev, ec_dev->dout);
409
410 ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
411 if (!ec_dev->din) {
412 ret = -ENOMEM;
413 goto exit;
414 }
415
416 ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
417 if (!ec_dev->dout) {
418 devm_kfree(dev, ec_dev->din);
419 ret = -ENOMEM;
420 goto exit;
421 }
422
423 /* Probe if MKBP event is supported */
424 ret = cros_ec_get_host_command_version_mask(ec_dev,
425 EC_CMD_GET_NEXT_EVENT,
426 &ver_mask);
427 if (ret < 0 || ver_mask == 0)
428 ec_dev->mkbp_event_supported = 0;
429 else
430 ec_dev->mkbp_event_supported = 1;
431
432 /* Probe if host sleep v1 is supported for S0ix failure detection. */
433 ret = cros_ec_get_host_command_version_mask(ec_dev,
434 EC_CMD_HOST_SLEEP_EVENT,
435 &ver_mask);
436 ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1)));
437
438 /*
439 * Get host event wake mask, assume all events are wake events
440 * if unavailable.
441 */
442 ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg,
443 &ec_dev->host_event_wake_mask);
444 if (ret < 0)
445 ec_dev->host_event_wake_mask = U32_MAX;
446
447 ret = 0;
448
449exit:
450 kfree(proto_msg);
451 return ret;
452}
453EXPORT_SYMBOL(cros_ec_query_all);
454
455int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
456 struct cros_ec_command *msg)
457{
458 int ret;
459
460 mutex_lock(&ec_dev->lock);
461 if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) {
462 ret = cros_ec_query_all(ec_dev);
463 if (ret) {
464 dev_err(ec_dev->dev,
465 "EC version unknown and query failed; aborting command\n");
466 mutex_unlock(&ec_dev->lock);
467 return ret;
468 }
469 }
470
471 if (msg->insize > ec_dev->max_response) {
472 dev_dbg(ec_dev->dev, "clamping message receive buffer\n");
473 msg->insize = ec_dev->max_response;
474 }
475
476 if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) {
477 if (msg->outsize > ec_dev->max_request) {
478 dev_err(ec_dev->dev,
479 "request of size %u is too big (max: %u)\n",
480 msg->outsize,
481 ec_dev->max_request);
482 mutex_unlock(&ec_dev->lock);
483 return -EMSGSIZE;
484 }
485 } else {
486 if (msg->outsize > ec_dev->max_passthru) {
487 dev_err(ec_dev->dev,
488 "passthru rq of size %u is too big (max: %u)\n",
489 msg->outsize,
490 ec_dev->max_passthru);
491 mutex_unlock(&ec_dev->lock);
492 return -EMSGSIZE;
493 }
494 }
495 ret = send_command(ec_dev, msg);
496 mutex_unlock(&ec_dev->lock);
497
498 return ret;
499}
500EXPORT_SYMBOL(cros_ec_cmd_xfer);
501
502int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
503 struct cros_ec_command *msg)
504{
505 int ret;
506
507 ret = cros_ec_cmd_xfer(ec_dev, msg);
508 if (ret < 0) {
509 dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
510 } else if (msg->result != EC_RES_SUCCESS) {
511 dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
512 return -EPROTO;
513 }
514
515 return ret;
516}
517EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
518
519static int get_next_event_xfer(struct cros_ec_device *ec_dev,
520 struct cros_ec_command *msg,
521 int version, uint32_t size)
522{
523 int ret;
524
525 msg->version = version;
526 msg->command = EC_CMD_GET_NEXT_EVENT;
527 msg->insize = size;
528 msg->outsize = 0;
529
530 ret = cros_ec_cmd_xfer(ec_dev, msg);
531 if (ret > 0) {
532 ec_dev->event_size = ret - 1;
533 memcpy(&ec_dev->event_data, msg->data, ret);
534 }
535
536 return ret;
537}
538
539static int get_next_event(struct cros_ec_device *ec_dev)
540{
541 u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
542 struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
543 static int cmd_version = 1;
544 int ret;
545
546 if (ec_dev->suspended) {
547 dev_dbg(ec_dev->dev, "Device suspended.\n");
548 return -EHOSTDOWN;
549 }
550
551 if (cmd_version == 1) {
552 ret = get_next_event_xfer(ec_dev, msg, cmd_version,
553 sizeof(struct ec_response_get_next_event_v1));
554 if (ret < 0 || msg->result != EC_RES_INVALID_VERSION)
555 return ret;
556
557 /* Fallback to version 0 for future send attempts */
558 cmd_version = 0;
559 }
560
561 ret = get_next_event_xfer(ec_dev, msg, cmd_version,
562 sizeof(struct ec_response_get_next_event));
563
564 return ret;
565}
566
567static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
568{
569 u8 buffer[sizeof(struct cros_ec_command) +
570 sizeof(ec_dev->event_data.data)];
571 struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
572
573 msg->version = 0;
574 msg->command = EC_CMD_MKBP_STATE;
575 msg->insize = sizeof(ec_dev->event_data.data);
576 msg->outsize = 0;
577
578 ec_dev->event_size = cros_ec_cmd_xfer(ec_dev, msg);
579 ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;
580 memcpy(&ec_dev->event_data.data, msg->data,
581 sizeof(ec_dev->event_data.data));
582
583 return ec_dev->event_size;
584}
585
586int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
587{
588 u8 event_type;
589 u32 host_event;
590 int ret;
591
592 if (!ec_dev->mkbp_event_supported) {
593 ret = get_keyboard_state_event(ec_dev);
594 if (ret <= 0)
595 return ret;
596
597 if (wake_event)
598 *wake_event = true;
599
600 return ret;
601 }
602
603 ret = get_next_event(ec_dev);
604 if (ret <= 0)
605 return ret;
606
607 if (wake_event) {
608 event_type = ec_dev->event_data.event_type;
609 host_event = cros_ec_get_host_event(ec_dev);
610
611 /*
612 * Sensor events need to be parsed by the sensor sub-device.
613 * Defer them, and don't report the wakeup here.
614 */
615 if (event_type == EC_MKBP_EVENT_SENSOR_FIFO)
616 *wake_event = false;
617 /* Masked host-events should not count as wake events. */
618 else if (host_event &&
619 !(host_event & ec_dev->host_event_wake_mask))
620 *wake_event = false;
621 /* Consider all other events as wake events. */
622 else
623 *wake_event = true;
624 }
625
626 return ret;
627}
628EXPORT_SYMBOL(cros_ec_get_next_event);
629
630u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
631{
632 u32 host_event;
633
634 BUG_ON(!ec_dev->mkbp_event_supported);
635
636 if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT)
637 return 0;
638
639 if (ec_dev->event_size != sizeof(host_event)) {
640 dev_warn(ec_dev->dev, "Invalid host event size\n");
641 return 0;
642 }
643
644 host_event = get_unaligned_le32(&ec_dev->event_data.data.host_event);
645
646 return host_event;
647}
648EXPORT_SYMBOL(cros_ec_get_host_event);