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