2 * ChromeOS EC communication protocol helper functions
4 * Copyright (C) 2015 Google, Inc
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.
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.
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>
23 #define EC_COMMAND_RETRIES 50
25 static int prepare_packet(struct cros_ec_device
*ec_dev
,
26 struct cros_ec_command
*msg
)
28 struct ec_host_request
*request
;
33 BUG_ON(ec_dev
->proto_version
!= EC_HOST_REQUEST_VERSION
);
34 BUG_ON(msg
->outsize
+ sizeof(*request
) > ec_dev
->dout_size
);
37 request
= (struct ec_host_request
*)out
;
38 request
->struct_version
= EC_HOST_REQUEST_VERSION
;
39 request
->checksum
= 0;
40 request
->command
= msg
->command
;
41 request
->command_version
= msg
->version
;
42 request
->reserved
= 0;
43 request
->data_len
= msg
->outsize
;
45 for (i
= 0; i
< sizeof(*request
); i
++)
48 /* Copy data and update checksum */
49 memcpy(out
+ sizeof(*request
), msg
->data
, msg
->outsize
);
50 for (i
= 0; i
< msg
->outsize
; i
++)
53 request
->checksum
= -csum
;
55 return sizeof(*request
) + msg
->outsize
;
58 static int send_command(struct cros_ec_device
*ec_dev
,
59 struct cros_ec_command
*msg
)
63 if (ec_dev
->proto_version
> 2)
64 ret
= ec_dev
->pkt_xfer(ec_dev
, msg
);
66 ret
= ec_dev
->cmd_xfer(ec_dev
, msg
);
68 if (msg
->result
== EC_RES_IN_PROGRESS
) {
70 struct cros_ec_command
*status_msg
;
71 struct ec_response_get_comms_status
*status
;
73 status_msg
= kmalloc(sizeof(*status_msg
) + sizeof(*status
),
78 status_msg
->version
= 0;
79 status_msg
->command
= EC_CMD_GET_COMMS_STATUS
;
80 status_msg
->insize
= sizeof(*status
);
81 status_msg
->outsize
= 0;
84 * Query the EC's status until it's no longer busy or
85 * we encounter an error.
87 for (i
= 0; i
< EC_COMMAND_RETRIES
; i
++) {
88 usleep_range(10000, 11000);
90 ret
= ec_dev
->cmd_xfer(ec_dev
, status_msg
);
94 msg
->result
= status_msg
->result
;
95 if (status_msg
->result
!= EC_RES_SUCCESS
)
98 status
= (struct ec_response_get_comms_status
*)
100 if (!(status
->flags
& EC_COMMS_STATUS_PROCESSING
))
110 int cros_ec_prepare_tx(struct cros_ec_device
*ec_dev
,
111 struct cros_ec_command
*msg
)
117 if (ec_dev
->proto_version
> 2)
118 return prepare_packet(ec_dev
, msg
);
120 BUG_ON(msg
->outsize
> EC_PROTO2_MAX_PARAM_SIZE
);
122 out
[0] = EC_CMD_VERSION0
+ msg
->version
;
123 out
[1] = msg
->command
;
124 out
[2] = msg
->outsize
;
125 csum
= out
[0] + out
[1] + out
[2];
126 for (i
= 0; i
< msg
->outsize
; i
++)
127 csum
+= out
[EC_MSG_TX_HEADER_BYTES
+ i
] = msg
->data
[i
];
128 out
[EC_MSG_TX_HEADER_BYTES
+ msg
->outsize
] = csum
;
130 return EC_MSG_TX_PROTO_BYTES
+ msg
->outsize
;
132 EXPORT_SYMBOL(cros_ec_prepare_tx
);
134 int cros_ec_check_result(struct cros_ec_device
*ec_dev
,
135 struct cros_ec_command
*msg
)
137 switch (msg
->result
) {
140 case EC_RES_IN_PROGRESS
:
141 dev_dbg(ec_dev
->dev
, "command 0x%02x in progress\n",
145 dev_dbg(ec_dev
->dev
, "command 0x%02x returned %d\n",
146 msg
->command
, msg
->result
);
150 EXPORT_SYMBOL(cros_ec_check_result
);
152 static int cros_ec_host_command_proto_query(struct cros_ec_device
*ec_dev
,
154 struct cros_ec_command
*msg
)
157 * Try using v3+ to query for supported protocols. If this
158 * command fails, fall back to v2. Returns the highest protocol
159 * supported by the EC.
160 * Also sets the max request/response/passthru size.
164 if (!ec_dev
->pkt_xfer
)
165 return -EPROTONOSUPPORT
;
167 memset(msg
, 0, sizeof(*msg
));
168 msg
->command
= EC_CMD_PASSTHRU_OFFSET(devidx
) | EC_CMD_GET_PROTOCOL_INFO
;
169 msg
->insize
= sizeof(struct ec_response_get_protocol_info
);
171 ret
= send_command(ec_dev
, msg
);
175 "failed to check for EC[%d] protocol version: %d\n",
180 if (devidx
> 0 && msg
->result
== EC_RES_INVALID_COMMAND
)
182 else if (msg
->result
!= EC_RES_SUCCESS
)
188 static int cros_ec_host_command_proto_query_v2(struct cros_ec_device
*ec_dev
)
190 struct cros_ec_command
*msg
;
191 struct ec_params_hello
*hello_params
;
192 struct ec_response_hello
*hello_response
;
194 int len
= max(sizeof(*hello_params
), sizeof(*hello_response
));
196 msg
= kmalloc(sizeof(*msg
) + len
, GFP_KERNEL
);
201 msg
->command
= EC_CMD_HELLO
;
202 hello_params
= (struct ec_params_hello
*)msg
->data
;
203 msg
->outsize
= sizeof(*hello_params
);
204 hello_response
= (struct ec_response_hello
*)msg
->data
;
205 msg
->insize
= sizeof(*hello_response
);
207 hello_params
->in_data
= 0xa0b0c0d0;
209 ret
= send_command(ec_dev
, msg
);
213 "EC failed to respond to v2 hello: %d\n",
216 } else if (msg
->result
!= EC_RES_SUCCESS
) {
218 "EC responded to v2 hello with error: %d\n",
222 } else if (hello_response
->out_data
!= 0xa1b2c3d4) {
224 "EC responded to v2 hello with bad result: %u\n",
225 hello_response
->out_data
);
237 int cros_ec_query_all(struct cros_ec_device
*ec_dev
)
239 struct device
*dev
= ec_dev
->dev
;
240 struct cros_ec_command
*proto_msg
;
241 struct ec_response_get_protocol_info
*proto_info
;
244 proto_msg
= kzalloc(sizeof(*proto_msg
) + sizeof(*proto_info
),
249 /* First try sending with proto v3. */
250 ec_dev
->proto_version
= 3;
251 ret
= cros_ec_host_command_proto_query(ec_dev
, 0, proto_msg
);
254 proto_info
= (struct ec_response_get_protocol_info
*)
256 ec_dev
->max_request
= proto_info
->max_request_packet_size
-
257 sizeof(struct ec_host_request
);
258 ec_dev
->max_response
= proto_info
->max_response_packet_size
-
259 sizeof(struct ec_host_response
);
260 ec_dev
->proto_version
=
261 min(EC_HOST_REQUEST_VERSION
,
262 fls(proto_info
->protocol_versions
) - 1);
265 ec_dev
->proto_version
);
267 ec_dev
->din_size
= ec_dev
->max_response
+
268 sizeof(struct ec_host_response
) +
269 EC_MAX_RESPONSE_OVERHEAD
;
270 ec_dev
->dout_size
= ec_dev
->max_request
+
271 sizeof(struct ec_host_request
) +
272 EC_MAX_REQUEST_OVERHEAD
;
277 ret
= cros_ec_host_command_proto_query(ec_dev
, 1, proto_msg
);
280 dev_dbg(ec_dev
->dev
, "no PD chip found: %d\n", ret
);
281 ec_dev
->max_passthru
= 0;
283 dev_dbg(ec_dev
->dev
, "found PD chip\n");
284 ec_dev
->max_passthru
=
285 proto_info
->max_request_packet_size
-
286 sizeof(struct ec_host_request
);
289 /* Try querying with a v2 hello message. */
290 ec_dev
->proto_version
= 2;
291 ret
= cros_ec_host_command_proto_query_v2(ec_dev
);
294 /* V2 hello succeeded. */
295 dev_dbg(ec_dev
->dev
, "falling back to proto v2\n");
297 ec_dev
->max_request
= EC_PROTO2_MAX_PARAM_SIZE
;
298 ec_dev
->max_response
= EC_PROTO2_MAX_PARAM_SIZE
;
299 ec_dev
->max_passthru
= 0;
300 ec_dev
->pkt_xfer
= NULL
;
301 ec_dev
->din_size
= EC_PROTO2_MSG_BYTES
;
302 ec_dev
->dout_size
= EC_PROTO2_MSG_BYTES
;
305 * It's possible for a test to occur too early when
306 * the EC isn't listening. If this happens, we'll
307 * test later when the first command is run.
309 ec_dev
->proto_version
= EC_PROTO_VERSION_UNKNOWN
;
310 dev_dbg(ec_dev
->dev
, "EC query failed: %d\n", ret
);
315 devm_kfree(dev
, ec_dev
->din
);
316 devm_kfree(dev
, ec_dev
->dout
);
318 ec_dev
->din
= devm_kzalloc(dev
, ec_dev
->din_size
, GFP_KERNEL
);
324 ec_dev
->dout
= devm_kzalloc(dev
, ec_dev
->dout_size
, GFP_KERNEL
);
326 devm_kfree(dev
, ec_dev
->din
);
335 EXPORT_SYMBOL(cros_ec_query_all
);
337 int cros_ec_cmd_xfer(struct cros_ec_device
*ec_dev
,
338 struct cros_ec_command
*msg
)
342 mutex_lock(&ec_dev
->lock
);
343 if (ec_dev
->proto_version
== EC_PROTO_VERSION_UNKNOWN
) {
344 ret
= cros_ec_query_all(ec_dev
);
347 "EC version unknown and query failed; aborting command\n");
348 mutex_unlock(&ec_dev
->lock
);
353 if (msg
->insize
> ec_dev
->max_response
) {
354 dev_dbg(ec_dev
->dev
, "clamping message receive buffer\n");
355 msg
->insize
= ec_dev
->max_response
;
358 if (msg
->command
< EC_CMD_PASSTHRU_OFFSET(1)) {
359 if (msg
->outsize
> ec_dev
->max_request
) {
361 "request of size %u is too big (max: %u)\n",
363 ec_dev
->max_request
);
364 mutex_unlock(&ec_dev
->lock
);
368 if (msg
->outsize
> ec_dev
->max_passthru
) {
370 "passthru rq of size %u is too big (max: %u)\n",
372 ec_dev
->max_passthru
);
373 mutex_unlock(&ec_dev
->lock
);
377 ret
= send_command(ec_dev
, msg
);
378 mutex_unlock(&ec_dev
->lock
);
382 EXPORT_SYMBOL(cros_ec_cmd_xfer
);