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