2 * This file is part of the coreboot project.
4 * Copyright (C) 2013 Google Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <console/console.h>
26 #include "ec_commands.h"
27 #include "ec_message.h"
29 /* Common utilities */
31 /* Dumps EC command / response data into debug output.
33 * @param name Message prefix name.
34 * @param cmd Command code, or -1 to ignore cmd message.
35 * @param data Data buffer to print.
36 * @param len Length of data.
38 static void cros_ec_dump_data(const char *name
, int cmd
, const uint8_t *data
,
43 printk(BIOS_DEBUG
, "%s: ", name
);
45 printk(BIOS_DEBUG
, "cmd=%#x: ", cmd
);
46 for (i
= 0; i
< len
; i
++)
47 printk(BIOS_DEBUG
, "%02x ", data
[i
]);
48 printk(BIOS_DEBUG
, "\n");
51 /* Calculate a simple 8-bit checksum of a data block
53 * @param data Data block to checksum
54 * @param size Size of data block in bytes
55 * @return checksum value (0 to 255)
57 static int cros_ec_calc_checksum(const uint8_t *data
, int size
)
61 for (i
= csum
= 0; i
< size
; i
++)
66 /* Standard Chrome EC protocol, version 3 */
68 struct ec_command_v3
{
69 struct ec_host_request header
;
70 uint8_t data
[MSG_BYTES
];
73 struct ec_response_v3
{
74 struct ec_host_response header
;
75 uint8_t data
[MSG_BYTES
];
79 * Create a request packet for protocol version 3.
81 * @param cec_command Command description.
82 * @param cmd Packed command bit stream.
83 * @return packet size in bytes, or <0 if error.
85 static int create_proto3_request(const struct chromeec_command
*cec_command
,
86 struct ec_command_v3
*cmd
)
88 struct ec_host_request
*rq
= &cmd
->header
;
89 int out_bytes
= cec_command
->cmd_size_in
+ sizeof(*rq
);
91 /* Fail if output size is too big */
92 if (out_bytes
> sizeof(*cmd
)) {
93 printk(BIOS_ERR
, "%s: Cannot send %d bytes\n", __func__
,
94 cec_command
->cmd_size_in
);
95 return -EC_RES_REQUEST_TRUNCATED
;
98 /* Fill in request packet */
99 rq
->struct_version
= EC_HOST_REQUEST_VERSION
;
101 rq
->command
= cec_command
->cmd_code
;
102 rq
->command_version
= cec_command
->cmd_version
;
104 rq
->data_len
= cec_command
->cmd_size_in
;
106 /* Copy data after header */
107 memcpy(cmd
->data
, cec_command
->cmd_data_in
, cec_command
->cmd_size_in
);
109 /* Write checksum field so the entire packet sums to 0 */
110 rq
->checksum
= (uint8_t)(-cros_ec_calc_checksum(
111 (const uint8_t*)cmd
, out_bytes
));
113 cros_ec_dump_data("out", rq
->command
, (const uint8_t *)cmd
, out_bytes
);
115 /* Return size of request packet */
120 * Prepare the device to receive a protocol version 3 response.
122 * @param cec_command Command description.
123 * @param resp Response buffer.
124 * @return maximum expected number of bytes in response, or <0 if error.
126 static int prepare_proto3_response_buffer(
127 const struct chromeec_command
*cec_command
,
128 struct ec_response_v3
*resp
)
130 int in_bytes
= cec_command
->cmd_size_out
+ sizeof(resp
->header
);
132 /* Fail if input size is too big */
133 if (in_bytes
> sizeof(*resp
)) {
134 printk(BIOS_ERR
, "%s: Cannot receive %d bytes\n", __func__
,
135 cec_command
->cmd_size_out
);
136 return -EC_RES_RESPONSE_TOO_BIG
;
139 /* Return expected size of response packet */
144 * Handle a protocol version 3 response packet.
146 * The packet must already be stored in the response buffer.
148 * @param resp Response buffer.
149 * @param cec_command Command structure to receive valid response.
150 * @return number of bytes of response data, or <0 if error
152 static int handle_proto3_response(struct ec_response_v3
*resp
,
153 struct chromeec_command
*cec_command
)
155 struct ec_host_response
*rs
= &resp
->header
;
159 cros_ec_dump_data("in-header", -1, (const uint8_t*)rs
, sizeof(*rs
));
161 /* Check input data */
162 if (rs
->struct_version
!= EC_HOST_RESPONSE_VERSION
) {
163 printk(BIOS_ERR
, "%s: EC response version mismatch\n", __func__
);
164 return -EC_RES_INVALID_RESPONSE
;
168 printk(BIOS_ERR
, "%s: EC response reserved != 0\n", __func__
);
169 return -EC_RES_INVALID_RESPONSE
;
172 if (rs
->data_len
> sizeof(resp
->data
) ||
173 rs
->data_len
> cec_command
->cmd_size_out
) {
174 printk(BIOS_ERR
, "%s: EC returned too much data\n", __func__
);
175 return -EC_RES_RESPONSE_TOO_BIG
;
178 cros_ec_dump_data("in-data", -1, resp
->data
, rs
->data_len
);
180 /* Update in_bytes to actual data size */
181 in_bytes
= sizeof(*rs
) + rs
->data_len
;
183 /* Verify checksum */
184 csum
= cros_ec_calc_checksum((const uint8_t *)resp
, in_bytes
);
186 printk(BIOS_ERR
, "%s: EC response checksum invalid: 0x%02x\n",
188 return -EC_RES_INVALID_CHECKSUM
;
191 /* Return raw response. */
192 cec_command
->cmd_code
= rs
->result
;
193 cec_command
->cmd_size_out
= rs
->data_len
;
194 memcpy(cec_command
->cmd_data_out
, resp
->data
, rs
->data_len
);
196 /* Return error result, if any */
198 printk(BIOS_ERR
, "%s: EC response with error code: %d\n",
199 __func__
, rs
->result
);
200 return -(int)rs
->result
;
206 static int send_command_proto3(struct chromeec_command
*cec_command
,
207 crosec_io_t crosec_io
, void *context
)
209 int out_bytes
, in_bytes
;
211 struct ec_command_v3 cmd
= { {0}, };
212 struct ec_response_v3 resp
= { {0}, };
214 /* Create request packet */
215 out_bytes
= create_proto3_request(cec_command
, &cmd
);
220 /* Prepare response buffer */
221 in_bytes
= prepare_proto3_response_buffer(cec_command
, &resp
);
226 rv
= crosec_io((uint8_t *)&cmd
, out_bytes
, (uint8_t *)&resp
, in_bytes
,
229 printk(BIOS_ERR
, "%s: failed to complete I/O: Err = %#x.",
230 __func__
, rv
>= 0 ? rv
: -rv
);
231 return -EC_RES_ERROR
;
234 /* Process the response */
235 return handle_proto3_response(&resp
, cec_command
);
238 static int crosec_command_proto_v3(struct chromeec_command
*cec_command
,
239 crosec_io_t crosec_io
, void *context
)
241 int rv
= send_command_proto3(cec_command
, crosec_io
, context
);
243 cec_command
->cmd_code
= rv
;
249 int crosec_command_proto(struct chromeec_command
*cec_command
,
250 crosec_io_t crosec_io
, void *context
)
252 // TODO(hungte) Detect and fallback to v2 if we need.
253 return crosec_command_proto_v3(cec_command
, crosec_io
, context
);