1109 lines · c
1// SPDX-License-Identifier: GPL-2.02// ChromeOS EC communication protocol helper functions3//4// Copyright (C) 2015 Google, Inc5 6#include <linux/delay.h>7#include <linux/device.h>8#include <linux/limits.h>9#include <linux/module.h>10#include <linux/platform_data/cros_ec_commands.h>11#include <linux/platform_data/cros_ec_proto.h>12#include <linux/slab.h>13#include <linux/unaligned.h>14 15#include "cros_ec_trace.h"16 17#define EC_COMMAND_RETRIES 5018 19static const int cros_ec_error_map[] = {20 [EC_RES_INVALID_COMMAND] = -EOPNOTSUPP,21 [EC_RES_ERROR] = -EIO,22 [EC_RES_INVALID_PARAM] = -EINVAL,23 [EC_RES_ACCESS_DENIED] = -EACCES,24 [EC_RES_INVALID_RESPONSE] = -EPROTO,25 [EC_RES_INVALID_VERSION] = -ENOPROTOOPT,26 [EC_RES_INVALID_CHECKSUM] = -EBADMSG,27 [EC_RES_IN_PROGRESS] = -EINPROGRESS,28 [EC_RES_UNAVAILABLE] = -ENODATA,29 [EC_RES_TIMEOUT] = -ETIMEDOUT,30 [EC_RES_OVERFLOW] = -EOVERFLOW,31 [EC_RES_INVALID_HEADER] = -EBADR,32 [EC_RES_REQUEST_TRUNCATED] = -EBADR,33 [EC_RES_RESPONSE_TOO_BIG] = -EFBIG,34 [EC_RES_BUS_ERROR] = -EFAULT,35 [EC_RES_BUSY] = -EBUSY,36 [EC_RES_INVALID_HEADER_VERSION] = -EBADMSG,37 [EC_RES_INVALID_HEADER_CRC] = -EBADMSG,38 [EC_RES_INVALID_DATA_CRC] = -EBADMSG,39 [EC_RES_DUP_UNAVAILABLE] = -ENODATA,40};41 42static int cros_ec_map_error(uint32_t result)43{44 int ret = 0;45 46 if (result != EC_RES_SUCCESS) {47 if (result < ARRAY_SIZE(cros_ec_error_map) && cros_ec_error_map[result])48 ret = cros_ec_error_map[result];49 else50 ret = -EPROTO;51 }52 53 return ret;54}55 56static int prepare_tx(struct cros_ec_device *ec_dev,57 struct cros_ec_command *msg)58{59 struct ec_host_request *request;60 u8 *out;61 int i;62 u8 csum = 0;63 64 if (msg->outsize + sizeof(*request) > ec_dev->dout_size)65 return -EINVAL;66 67 out = ec_dev->dout;68 request = (struct ec_host_request *)out;69 request->struct_version = EC_HOST_REQUEST_VERSION;70 request->checksum = 0;71 request->command = msg->command;72 request->command_version = msg->version;73 request->reserved = 0;74 request->data_len = msg->outsize;75 76 for (i = 0; i < sizeof(*request); i++)77 csum += out[i];78 79 /* Copy data and update checksum */80 memcpy(out + sizeof(*request), msg->data, msg->outsize);81 for (i = 0; i < msg->outsize; i++)82 csum += msg->data[i];83 84 request->checksum = -csum;85 86 return sizeof(*request) + msg->outsize;87}88 89static int prepare_tx_legacy(struct cros_ec_device *ec_dev,90 struct cros_ec_command *msg)91{92 u8 *out;93 u8 csum;94 int i;95 96 if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE)97 return -EINVAL;98 99 out = ec_dev->dout;100 out[0] = EC_CMD_VERSION0 + msg->version;101 out[1] = msg->command;102 out[2] = msg->outsize;103 csum = out[0] + out[1] + out[2];104 for (i = 0; i < msg->outsize; i++)105 csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];106 out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum;107 108 return EC_MSG_TX_PROTO_BYTES + msg->outsize;109}110 111static int cros_ec_xfer_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)112{113 int ret;114 int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg);115 116 if (ec_dev->proto_version > 2)117 xfer_fxn = ec_dev->pkt_xfer;118 else119 xfer_fxn = ec_dev->cmd_xfer;120 121 if (!xfer_fxn) {122 /*123 * This error can happen if a communication error happened and124 * the EC is trying to use protocol v2, on an underlying125 * communication mechanism that does not support v2.126 */127 dev_err_once(ec_dev->dev, "missing EC transfer API, cannot send command\n");128 return -EIO;129 }130 131 trace_cros_ec_request_start(msg);132 ret = (*xfer_fxn)(ec_dev, msg);133 trace_cros_ec_request_done(msg, ret);134 135 return ret;136}137 138static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t *result)139{140 struct {141 struct cros_ec_command msg;142 struct ec_response_get_comms_status status;143 } __packed buf;144 struct cros_ec_command *msg = &buf.msg;145 struct ec_response_get_comms_status *status = &buf.status;146 int ret = 0, i;147 148 msg->version = 0;149 msg->command = EC_CMD_GET_COMMS_STATUS;150 msg->insize = sizeof(*status);151 msg->outsize = 0;152 153 /* Query the EC's status until it's no longer busy or we encounter an error. */154 for (i = 0; i < EC_COMMAND_RETRIES; ++i) {155 usleep_range(10000, 11000);156 157 ret = cros_ec_xfer_command(ec_dev, msg);158 if (ret == -EAGAIN)159 continue;160 if (ret < 0)161 return ret;162 163 *result = msg->result;164 if (msg->result != EC_RES_SUCCESS)165 return ret;166 167 if (ret == 0) {168 ret = -EPROTO;169 break;170 }171 172 if (!(status->flags & EC_COMMS_STATUS_PROCESSING))173 return ret;174 }175 176 if (i >= EC_COMMAND_RETRIES)177 ret = -EAGAIN;178 179 return ret;180}181 182static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)183{184 int ret = cros_ec_xfer_command(ec_dev, msg);185 186 if (msg->result == EC_RES_IN_PROGRESS)187 ret = cros_ec_wait_until_complete(ec_dev, &msg->result);188 189 return ret;190}191 192/**193 * cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.194 * @ec_dev: Device to register.195 * @msg: Message to write.196 *197 * This is used by all ChromeOS EC drivers to prepare the outgoing message198 * according to different protocol versions.199 *200 * Return: number of prepared bytes on success or negative error code.201 */202int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,203 struct cros_ec_command *msg)204{205 if (ec_dev->proto_version > 2)206 return prepare_tx(ec_dev, msg);207 208 return prepare_tx_legacy(ec_dev, msg);209}210EXPORT_SYMBOL(cros_ec_prepare_tx);211 212/**213 * cros_ec_check_result() - Check ec_msg->result.214 * @ec_dev: EC device.215 * @msg: Message to check.216 *217 * This is used by ChromeOS EC drivers to check the ec_msg->result for218 * EC_RES_IN_PROGRESS and to warn about them.219 *220 * The function should not check for furthermore error codes. Otherwise,221 * it would break the ABI.222 *223 * Return: -EAGAIN if ec_msg->result == EC_RES_IN_PROGRESS. Otherwise, 0.224 */225int cros_ec_check_result(struct cros_ec_device *ec_dev,226 struct cros_ec_command *msg)227{228 switch (msg->result) {229 case EC_RES_SUCCESS:230 return 0;231 case EC_RES_IN_PROGRESS:232 dev_dbg(ec_dev->dev, "command 0x%02x in progress\n",233 msg->command);234 return -EAGAIN;235 default:236 dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n",237 msg->command, msg->result);238 return 0;239 }240}241EXPORT_SYMBOL(cros_ec_check_result);242 243/**244 * cros_ec_get_host_event_wake_mask245 *246 * Get the mask of host events that cause wake from suspend.247 *248 * @ec_dev: EC device to call249 * @mask: result when function returns 0.250 *251 * LOCKING:252 * the caller has ec_dev->lock mutex, or the caller knows there is253 * no other command in progress.254 */255static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint32_t *mask)256{257 struct cros_ec_command *msg;258 struct ec_response_host_event_mask *r;259 int ret, mapped;260 261 msg = kzalloc(sizeof(*msg) + sizeof(*r), GFP_KERNEL);262 if (!msg)263 return -ENOMEM;264 265 msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK;266 msg->insize = sizeof(*r);267 268 ret = cros_ec_send_command(ec_dev, msg);269 if (ret < 0)270 goto exit;271 272 mapped = cros_ec_map_error(msg->result);273 if (mapped) {274 ret = mapped;275 goto exit;276 }277 278 if (ret == 0) {279 ret = -EPROTO;280 goto exit;281 }282 283 r = (struct ec_response_host_event_mask *)msg->data;284 *mask = r->mask;285 ret = 0;286exit:287 kfree(msg);288 return ret;289}290 291static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx)292{293 struct cros_ec_command *msg;294 struct ec_response_get_protocol_info *info;295 int ret, mapped;296 297 ec_dev->proto_version = 3;298 if (devidx > 0)299 ec_dev->max_passthru = 0;300 301 msg = kzalloc(sizeof(*msg) + sizeof(*info), GFP_KERNEL);302 if (!msg)303 return -ENOMEM;304 305 msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO;306 msg->insize = sizeof(*info);307 308 ret = cros_ec_send_command(ec_dev, msg);309 /*310 * Send command once again when timeout occurred.311 * Fingerprint MCU (FPMCU) is restarted during system boot which312 * introduces small window in which FPMCU won't respond for any313 * messages sent by kernel. There is no need to wait before next314 * attempt because we waited at least EC_MSG_DEADLINE_MS.315 */316 if (ret == -ETIMEDOUT)317 ret = cros_ec_send_command(ec_dev, msg);318 319 if (ret < 0) {320 dev_dbg(ec_dev->dev,321 "failed to check for EC[%d] protocol version: %d\n",322 devidx, ret);323 goto exit;324 }325 326 mapped = cros_ec_map_error(msg->result);327 if (mapped) {328 ret = mapped;329 goto exit;330 }331 332 if (ret == 0) {333 ret = -EPROTO;334 goto exit;335 }336 337 info = (struct ec_response_get_protocol_info *)msg->data;338 339 switch (devidx) {340 case CROS_EC_DEV_EC_INDEX:341 ec_dev->max_request = info->max_request_packet_size -342 sizeof(struct ec_host_request);343 ec_dev->max_response = info->max_response_packet_size -344 sizeof(struct ec_host_response);345 ec_dev->proto_version = min(EC_HOST_REQUEST_VERSION,346 fls(info->protocol_versions) - 1);347 ec_dev->din_size = info->max_response_packet_size + EC_MAX_RESPONSE_OVERHEAD;348 ec_dev->dout_size = info->max_request_packet_size + EC_MAX_REQUEST_OVERHEAD;349 350 dev_dbg(ec_dev->dev, "using proto v%u\n", ec_dev->proto_version);351 break;352 case CROS_EC_DEV_PD_INDEX:353 ec_dev->max_passthru = info->max_request_packet_size -354 sizeof(struct ec_host_request);355 356 dev_dbg(ec_dev->dev, "found PD chip\n");357 break;358 default:359 dev_dbg(ec_dev->dev, "unknown passthru index: %d\n", devidx);360 break;361 }362 363 ret = 0;364exit:365 kfree(msg);366 return ret;367}368 369static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev)370{371 struct cros_ec_command *msg;372 struct ec_params_hello *params;373 struct ec_response_hello *response;374 int ret, mapped;375 376 ec_dev->proto_version = 2;377 378 msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*response)), GFP_KERNEL);379 if (!msg)380 return -ENOMEM;381 382 msg->command = EC_CMD_HELLO;383 msg->insize = sizeof(*response);384 msg->outsize = sizeof(*params);385 386 params = (struct ec_params_hello *)msg->data;387 params->in_data = 0xa0b0c0d0;388 389 ret = cros_ec_send_command(ec_dev, msg);390 if (ret < 0) {391 dev_dbg(ec_dev->dev, "EC failed to respond to v2 hello: %d\n", ret);392 goto exit;393 }394 395 mapped = cros_ec_map_error(msg->result);396 if (mapped) {397 ret = mapped;398 dev_err(ec_dev->dev, "EC responded to v2 hello with error: %d\n", msg->result);399 goto exit;400 }401 402 if (ret == 0) {403 ret = -EPROTO;404 goto exit;405 }406 407 response = (struct ec_response_hello *)msg->data;408 if (response->out_data != 0xa1b2c3d4) {409 dev_err(ec_dev->dev,410 "EC responded to v2 hello with bad result: %u\n",411 response->out_data);412 ret = -EBADMSG;413 goto exit;414 }415 416 ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE;417 ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE;418 ec_dev->max_passthru = 0;419 ec_dev->pkt_xfer = NULL;420 ec_dev->din_size = EC_PROTO2_MSG_BYTES;421 ec_dev->dout_size = EC_PROTO2_MSG_BYTES;422 423 dev_dbg(ec_dev->dev, "falling back to proto v2\n");424 ret = 0;425exit:426 kfree(msg);427 return ret;428}429 430/**431 * cros_ec_get_host_command_version_mask432 *433 * Get the version mask of a given command.434 *435 * @ec_dev: EC device to call436 * @cmd: command to get the version of.437 * @mask: result when function returns 0.438 *439 * @return 0 on success, error code otherwise440 *441 * LOCKING:442 * the caller has ec_dev->lock mutex or the caller knows there is443 * no other command in progress.444 */445static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, u16 cmd, u32 *mask)446{447 struct ec_params_get_cmd_versions *pver;448 struct ec_response_get_cmd_versions *rver;449 struct cros_ec_command *msg;450 int ret, mapped;451 452 msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),453 GFP_KERNEL);454 if (!msg)455 return -ENOMEM;456 457 msg->version = 0;458 msg->command = EC_CMD_GET_CMD_VERSIONS;459 msg->insize = sizeof(*rver);460 msg->outsize = sizeof(*pver);461 462 pver = (struct ec_params_get_cmd_versions *)msg->data;463 pver->cmd = cmd;464 465 ret = cros_ec_send_command(ec_dev, msg);466 if (ret < 0)467 goto exit;468 469 mapped = cros_ec_map_error(msg->result);470 if (mapped) {471 ret = mapped;472 goto exit;473 }474 475 if (ret == 0) {476 ret = -EPROTO;477 goto exit;478 }479 480 rver = (struct ec_response_get_cmd_versions *)msg->data;481 *mask = rver->version_mask;482 ret = 0;483exit:484 kfree(msg);485 return ret;486}487 488/**489 * cros_ec_query_all() - Query the protocol version supported by the490 * ChromeOS EC.491 * @ec_dev: Device to register.492 *493 * Return: 0 on success or negative error code.494 */495int cros_ec_query_all(struct cros_ec_device *ec_dev)496{497 struct device *dev = ec_dev->dev;498 u32 ver_mask;499 int ret;500 501 /* First try sending with proto v3. */502 if (!cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_EC_INDEX)) {503 /* Check for PD. */504 cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_PD_INDEX);505 } else {506 /* Try querying with a v2 hello message. */507 ret = cros_ec_get_proto_info_legacy(ec_dev);508 if (ret) {509 /*510 * It's possible for a test to occur too early when511 * the EC isn't listening. If this happens, we'll512 * test later when the first command is run.513 */514 ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN;515 dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret);516 return ret;517 }518 }519 520 devm_kfree(dev, ec_dev->din);521 devm_kfree(dev, ec_dev->dout);522 523 ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);524 if (!ec_dev->din) {525 ret = -ENOMEM;526 goto exit;527 }528 529 ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);530 if (!ec_dev->dout) {531 devm_kfree(dev, ec_dev->din);532 ret = -ENOMEM;533 goto exit;534 }535 536 /* Probe if MKBP event is supported */537 ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_GET_NEXT_EVENT, &ver_mask);538 if (ret < 0 || ver_mask == 0) {539 ec_dev->mkbp_event_supported = 0;540 } else {541 ec_dev->mkbp_event_supported = fls(ver_mask);542 543 dev_dbg(ec_dev->dev, "MKBP support version %u\n", ec_dev->mkbp_event_supported - 1);544 }545 546 /* Probe if host sleep v1 is supported for S0ix failure detection. */547 ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_HOST_SLEEP_EVENT, &ver_mask);548 ec_dev->host_sleep_v1 = (ret == 0 && (ver_mask & EC_VER_MASK(1)));549 550 /* Get host event wake mask. */551 ret = cros_ec_get_host_event_wake_mask(ec_dev, &ec_dev->host_event_wake_mask);552 if (ret < 0) {553 /*554 * If the EC doesn't support EC_CMD_HOST_EVENT_GET_WAKE_MASK,555 * use a reasonable default. Note that we ignore various556 * battery, AC status, and power-state events, because (a)557 * those can be quite common (e.g., when sitting at full558 * charge, on AC) and (b) these are not actionable wake events;559 * if anything, we'd like to continue suspending (to save560 * power), not wake up.561 */562 ec_dev->host_event_wake_mask = U32_MAX &563 ~(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED) |564 EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED) |565 EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_LOW) |566 EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_CRITICAL) |567 EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY) |568 EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU) |569 EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_STATUS));570 /*571 * Old ECs may not support this command. Complain about all572 * other errors.573 */574 if (ret != -EOPNOTSUPP)575 dev_err(ec_dev->dev,576 "failed to retrieve wake mask: %d\n", ret);577 }578 579 ret = 0;580 581exit:582 return ret;583}584EXPORT_SYMBOL(cros_ec_query_all);585 586/**587 * cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.588 * @ec_dev: EC device.589 * @msg: Message to write.590 *591 * Call this to send a command to the ChromeOS EC. This should be used instead592 * of calling the EC's cmd_xfer() callback directly. This function does not593 * convert EC command execution error codes to Linux error codes. Most594 * in-kernel users will want to use cros_ec_cmd_xfer_status() instead since595 * that function implements the conversion.596 *597 * Return:598 * >0 - EC command was executed successfully. The return value is the number599 * of bytes returned by the EC (excluding the header).600 * =0 - EC communication was successful. EC command execution results are601 * reported in msg->result. The result will be EC_RES_SUCCESS if the602 * command was executed successfully or report an EC command execution603 * error.604 * <0 - EC communication error. Return value is the Linux error code.605 */606int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)607{608 int ret;609 610 mutex_lock(&ec_dev->lock);611 if (ec_dev->proto_version == EC_PROTO_VERSION_UNKNOWN) {612 ret = cros_ec_query_all(ec_dev);613 if (ret) {614 dev_err(ec_dev->dev,615 "EC version unknown and query failed; aborting command\n");616 mutex_unlock(&ec_dev->lock);617 return ret;618 }619 }620 621 if (msg->insize > ec_dev->max_response) {622 dev_dbg(ec_dev->dev, "clamping message receive buffer\n");623 msg->insize = ec_dev->max_response;624 }625 626 if (msg->command < EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX)) {627 if (msg->outsize > ec_dev->max_request) {628 dev_err(ec_dev->dev,629 "request of size %u is too big (max: %u)\n",630 msg->outsize,631 ec_dev->max_request);632 mutex_unlock(&ec_dev->lock);633 return -EMSGSIZE;634 }635 } else {636 if (msg->outsize > ec_dev->max_passthru) {637 dev_err(ec_dev->dev,638 "passthru rq of size %u is too big (max: %u)\n",639 msg->outsize,640 ec_dev->max_passthru);641 mutex_unlock(&ec_dev->lock);642 return -EMSGSIZE;643 }644 }645 646 ret = cros_ec_send_command(ec_dev, msg);647 mutex_unlock(&ec_dev->lock);648 649 return ret;650}651EXPORT_SYMBOL(cros_ec_cmd_xfer);652 653/**654 * cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.655 * @ec_dev: EC device.656 * @msg: Message to write.657 *658 * Call this to send a command to the ChromeOS EC. This should be used instead of calling the EC's659 * cmd_xfer() callback directly. It returns success status only if both the command was transmitted660 * successfully and the EC replied with success status.661 *662 * Return:663 * >=0 - The number of bytes transferred.664 * <0 - Linux error code665 */666int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,667 struct cros_ec_command *msg)668{669 int ret, mapped;670 671 ret = cros_ec_cmd_xfer(ec_dev, msg);672 if (ret < 0)673 return ret;674 675 mapped = cros_ec_map_error(msg->result);676 if (mapped) {677 dev_dbg(ec_dev->dev, "Command result (err: %d [%d])\n",678 msg->result, mapped);679 ret = mapped;680 }681 682 return ret;683}684EXPORT_SYMBOL(cros_ec_cmd_xfer_status);685 686static int get_next_event_xfer(struct cros_ec_device *ec_dev,687 struct cros_ec_command *msg,688 struct ec_response_get_next_event_v3 *event,689 int version, uint32_t size)690{691 int ret;692 693 msg->version = version;694 msg->command = EC_CMD_GET_NEXT_EVENT;695 msg->insize = size;696 msg->outsize = 0;697 698 ret = cros_ec_cmd_xfer_status(ec_dev, msg);699 if (ret > 0) {700 ec_dev->event_size = ret - 1;701 ec_dev->event_data = *event;702 }703 704 return ret;705}706 707static int get_next_event(struct cros_ec_device *ec_dev)708{709 struct {710 struct cros_ec_command msg;711 struct ec_response_get_next_event_v3 event;712 } __packed buf;713 struct cros_ec_command *msg = &buf.msg;714 struct ec_response_get_next_event_v3 *event = &buf.event;715 int cmd_version = ec_dev->mkbp_event_supported - 1;716 u32 size;717 718 memset(msg, 0, sizeof(*msg));719 if (ec_dev->suspended) {720 dev_dbg(ec_dev->dev, "Device suspended.\n");721 return -EHOSTDOWN;722 }723 724 if (cmd_version == 0) {725 size = sizeof(struct ec_response_get_next_event);726 } else if (cmd_version < 3) {727 size = sizeof(struct ec_response_get_next_event_v1);728 } else {729 /*730 * The max version we support is v3. So, we speak v3 even if the731 * EC says it supports v4+.732 */733 cmd_version = 3;734 size = sizeof(struct ec_response_get_next_event_v3);735 }736 737 return get_next_event_xfer(ec_dev, msg, event, cmd_version, size);738}739 740static int get_keyboard_state_event(struct cros_ec_device *ec_dev)741{742 u8 buffer[sizeof(struct cros_ec_command) +743 sizeof(ec_dev->event_data.data)];744 struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;745 746 msg->version = 0;747 msg->command = EC_CMD_MKBP_STATE;748 msg->insize = sizeof(ec_dev->event_data.data);749 msg->outsize = 0;750 751 ec_dev->event_size = cros_ec_cmd_xfer_status(ec_dev, msg);752 ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;753 memcpy(&ec_dev->event_data.data, msg->data,754 sizeof(ec_dev->event_data.data));755 756 return ec_dev->event_size;757}758 759/**760 * cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.761 * @ec_dev: Device to fetch event from.762 * @wake_event: Pointer to a bool set to true upon return if the event might be763 * treated as a wake event. Ignored if null.764 * @has_more_events: Pointer to bool set to true if more than one event is765 * pending.766 * Some EC will set this flag to indicate cros_ec_get_next_event()767 * can be called multiple times in a row.768 * It is an optimization to prevent issuing a EC command for769 * nothing or wait for another interrupt from the EC to process770 * the next message.771 * Ignored if null.772 *773 * Return: negative error code on errors; 0 for no data; or else number of774 * bytes received (i.e., an event was retrieved successfully). Event types are775 * written out to @ec_dev->event_data.event_type on success.776 */777int cros_ec_get_next_event(struct cros_ec_device *ec_dev,778 bool *wake_event,779 bool *has_more_events)780{781 u8 event_type;782 u32 host_event;783 int ret;784 u32 ver_mask;785 786 /*787 * Default value for wake_event.788 * Wake up on keyboard event, wake up for spurious interrupt or link789 * error to the EC.790 */791 if (wake_event)792 *wake_event = true;793 794 /*795 * Default value for has_more_events.796 * EC will raise another interrupt if AP does not process all events797 * anyway.798 */799 if (has_more_events)800 *has_more_events = false;801 802 if (!ec_dev->mkbp_event_supported)803 return get_keyboard_state_event(ec_dev);804 805 ret = get_next_event(ec_dev);806 /*807 * -ENOPROTOOPT is returned when EC returns EC_RES_INVALID_VERSION.808 * This can occur when EC based device (e.g. Fingerprint MCU) jumps to809 * the RO image which doesn't support newer version of the command. In810 * this case we will attempt to update maximum supported version of the811 * EC_CMD_GET_NEXT_EVENT.812 */813 if (ret == -ENOPROTOOPT) {814 dev_dbg(ec_dev->dev,815 "GET_NEXT_EVENT returned invalid version error.\n");816 mutex_lock(&ec_dev->lock);817 ret = cros_ec_get_host_command_version_mask(ec_dev,818 EC_CMD_GET_NEXT_EVENT,819 &ver_mask);820 mutex_unlock(&ec_dev->lock);821 if (ret < 0 || ver_mask == 0)822 /*823 * Do not change the MKBP supported version if we can't824 * obtain supported version correctly. Please note that825 * calling EC_CMD_GET_NEXT_EVENT returned826 * EC_RES_INVALID_VERSION which means that the command827 * is present.828 */829 return -ENOPROTOOPT;830 831 ec_dev->mkbp_event_supported = fls(ver_mask);832 dev_dbg(ec_dev->dev, "MKBP support version changed to %u\n",833 ec_dev->mkbp_event_supported - 1);834 835 /* Try to get next event with new MKBP support version set. */836 ret = get_next_event(ec_dev);837 }838 839 if (ret <= 0)840 return ret;841 842 if (has_more_events)843 *has_more_events = ec_dev->event_data.event_type &844 EC_MKBP_HAS_MORE_EVENTS;845 ec_dev->event_data.event_type &= EC_MKBP_EVENT_TYPE_MASK;846 847 if (wake_event) {848 event_type = ec_dev->event_data.event_type;849 host_event = cros_ec_get_host_event(ec_dev);850 851 /*852 * Sensor events need to be parsed by the sensor sub-device.853 * Defer them, and don't report the wakeup here.854 */855 if (event_type == EC_MKBP_EVENT_SENSOR_FIFO) {856 *wake_event = false;857 } else if (host_event) {858 /* rtc_update_irq() already handles wakeup events. */859 if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC))860 *wake_event = false;861 /* Masked host-events should not count as wake events. */862 if (!(host_event & ec_dev->host_event_wake_mask))863 *wake_event = false;864 }865 }866 867 return ret;868}869EXPORT_SYMBOL(cros_ec_get_next_event);870 871/**872 * cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.873 * @ec_dev: Device to fetch event from.874 *875 * When MKBP is supported, when the EC raises an interrupt, we collect the876 * events raised and call the functions in the ec notifier. This function877 * is a helper to know which events are raised.878 *879 * Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.880 */881u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)882{883 u32 host_event;884 885 if (!ec_dev->mkbp_event_supported)886 return 0;887 888 if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT)889 return 0;890 891 if (ec_dev->event_size != sizeof(host_event)) {892 dev_warn(ec_dev->dev, "Invalid host event size\n");893 return 0;894 }895 896 host_event = get_unaligned_le32(&ec_dev->event_data.data.host_event);897 898 return host_event;899}900EXPORT_SYMBOL(cros_ec_get_host_event);901 902/**903 * cros_ec_check_features() - Test for the presence of EC features904 *905 * @ec: EC device, does not have to be connected directly to the AP,906 * can be daisy chained through another device.907 * @feature: One of ec_feature_code bit.908 *909 * Call this function to test whether the ChromeOS EC supports a feature.910 *911 * Return: true if supported, false if not (or if an error was encountered).912 */913bool cros_ec_check_features(struct cros_ec_dev *ec, int feature)914{915 struct ec_response_get_features *features = &ec->features;916 int ret;917 918 if (features->flags[0] == -1U && features->flags[1] == -1U) {919 /* features bitmap not read yet */920 ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset,921 NULL, 0, features, sizeof(*features));922 if (ret < 0) {923 dev_warn(ec->dev, "cannot get EC features: %d\n", ret);924 memset(features, 0, sizeof(*features));925 }926 927 dev_dbg(ec->dev, "EC features %08x %08x\n",928 features->flags[0], features->flags[1]);929 }930 931 return !!(features->flags[feature / 32] & EC_FEATURE_MASK_0(feature));932}933EXPORT_SYMBOL_GPL(cros_ec_check_features);934 935/**936 * cros_ec_get_sensor_count() - Return the number of MEMS sensors supported.937 *938 * @ec: EC device, does not have to be connected directly to the AP,939 * can be daisy chained through another device.940 * Return: < 0 in case of error.941 */942int cros_ec_get_sensor_count(struct cros_ec_dev *ec)943{944 /*945 * Issue a command to get the number of sensor reported.946 * If not supported, check for legacy mode.947 */948 int ret, sensor_count;949 struct ec_params_motion_sense *params;950 struct ec_response_motion_sense *resp;951 struct cros_ec_command *msg;952 struct cros_ec_device *ec_dev = ec->ec_dev;953 u8 status;954 955 msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)),956 GFP_KERNEL);957 if (!msg)958 return -ENOMEM;959 960 msg->version = 1;961 msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;962 msg->outsize = sizeof(*params);963 msg->insize = sizeof(*resp);964 965 params = (struct ec_params_motion_sense *)msg->data;966 params->cmd = MOTIONSENSE_CMD_DUMP;967 968 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);969 if (ret < 0) {970 sensor_count = ret;971 } else {972 resp = (struct ec_response_motion_sense *)msg->data;973 sensor_count = resp->dump.sensor_count;974 }975 kfree(msg);976 977 /*978 * Check legacy mode: Let's find out if sensors are accessible979 * via LPC interface.980 */981 if (sensor_count < 0 && ec->cmd_offset == 0 && ec_dev->cmd_readmem) {982 ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS,983 1, &status);984 if (ret >= 0 &&985 (status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {986 /*987 * We have 2 sensors, one in the lid, one in the base.988 */989 sensor_count = 2;990 } else {991 /*992 * EC uses LPC interface and no sensors are presented.993 */994 sensor_count = 0;995 }996 }997 return sensor_count;998}999EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);1000 1001/**1002 * cros_ec_cmd - Send a command to the EC.1003 *1004 * @ec_dev: EC device1005 * @version: EC command version1006 * @command: EC command1007 * @outdata: EC command output data1008 * @outsize: Size of outdata1009 * @indata: EC command input data1010 * @insize: Size of indata1011 *1012 * Return: >= 0 on success, negative error number on failure.1013 */1014int cros_ec_cmd(struct cros_ec_device *ec_dev,1015 unsigned int version,1016 int command,1017 const void *outdata,1018 size_t outsize,1019 void *indata,1020 size_t insize)1021{1022 struct cros_ec_command *msg;1023 int ret;1024 1025 msg = kzalloc(sizeof(*msg) + max(insize, outsize), GFP_KERNEL);1026 if (!msg)1027 return -ENOMEM;1028 1029 msg->version = version;1030 msg->command = command;1031 msg->outsize = outsize;1032 msg->insize = insize;1033 1034 if (outsize)1035 memcpy(msg->data, outdata, outsize);1036 1037 ret = cros_ec_cmd_xfer_status(ec_dev, msg);1038 if (ret < 0)1039 goto error;1040 1041 if (insize)1042 memcpy(indata, msg->data, insize);1043error:1044 kfree(msg);1045 return ret;1046}1047EXPORT_SYMBOL_GPL(cros_ec_cmd);1048 1049/**1050 * cros_ec_cmd_readmem - Read from EC memory.1051 *1052 * @ec_dev: EC device1053 * @offset: Is within EC_LPC_ADDR_MEMMAP region.1054 * @size: Number of bytes to read.1055 * @dest: EC command output data1056 *1057 * Return: >= 0 on success, negative error number on failure.1058 */1059int cros_ec_cmd_readmem(struct cros_ec_device *ec_dev, u8 offset, u8 size, void *dest)1060{1061 struct ec_params_read_memmap params = {};1062 1063 if (!size)1064 return -EINVAL;1065 1066 if (ec_dev->cmd_readmem)1067 return ec_dev->cmd_readmem(ec_dev, offset, size, dest);1068 1069 params.offset = offset;1070 params.size = size;1071 return cros_ec_cmd(ec_dev, 0, EC_CMD_READ_MEMMAP,1072 ¶ms, sizeof(params), dest, size);1073}1074EXPORT_SYMBOL_GPL(cros_ec_cmd_readmem);1075 1076/**1077 * cros_ec_get_cmd_versions - Get supported version mask.1078 *1079 * @ec_dev: EC device1080 * @cmd: Command to test1081 *1082 * Return: version mask on success, negative error number on failure.1083 */1084int cros_ec_get_cmd_versions(struct cros_ec_device *ec_dev, u16 cmd)1085{1086 struct ec_params_get_cmd_versions req_v0;1087 struct ec_params_get_cmd_versions_v1 req_v1;1088 struct ec_response_get_cmd_versions resp;1089 int ret;1090 1091 if (cmd <= U8_MAX) {1092 req_v0.cmd = cmd;1093 ret = cros_ec_cmd(ec_dev, 0, EC_CMD_GET_CMD_VERSIONS,1094 &req_v0, sizeof(req_v0), &resp, sizeof(resp));1095 } else {1096 req_v1.cmd = cmd;1097 ret = cros_ec_cmd(ec_dev, 1, EC_CMD_GET_CMD_VERSIONS,1098 &req_v1, sizeof(req_v1), &resp, sizeof(resp));1099 }1100 1101 if (ret == -EINVAL)1102 return 0; /* Command not implemented */1103 else if (ret < 0)1104 return ret;1105 else1106 return resp.version_mask;1107}1108EXPORT_SYMBOL_GPL(cros_ec_get_cmd_versions);1109