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 
17 static 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 
50 static 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 
119 int 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 }
141 EXPORT_SYMBOL(cros_ec_prepare_tx);
142 
143 int 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 }
159 EXPORT_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  */
174 static 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 
195 static 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 
231 static 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  */
296 static 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 
328 int 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 
449 exit:
450 	kfree(proto_msg);
451 	return ret;
452 }
453 EXPORT_SYMBOL(cros_ec_query_all);
454 
455 int 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 }
500 EXPORT_SYMBOL(cros_ec_cmd_xfer);
501 
502 int 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 }
517 EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
518 
519 static 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 
539 static 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 
567 static 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 
586 int 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 }
628 EXPORT_SYMBOL(cros_ec_get_next_event);
629 
630 u32 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 }
648 EXPORT_SYMBOL(cros_ec_get_host_event);
649