1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Chromium OS cros_ec driver
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 2012 The Chromium OS Authors.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun /*
10*4882a593Smuzhiyun * This is the interface to the Chrome OS EC. It provides keyboard functions,
11*4882a593Smuzhiyun * power control and battery management. Quite a few other functions are
12*4882a593Smuzhiyun * provided to enable the EC software to be updated, talk to the EC's I2C bus
13*4882a593Smuzhiyun * and store a small amount of data in a memory which persists while the EC
14*4882a593Smuzhiyun * is not reset.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <common.h>
18*4882a593Smuzhiyun #include <command.h>
19*4882a593Smuzhiyun #include <dm.h>
20*4882a593Smuzhiyun #include <i2c.h>
21*4882a593Smuzhiyun #include <cros_ec.h>
22*4882a593Smuzhiyun #include <fdtdec.h>
23*4882a593Smuzhiyun #include <malloc.h>
24*4882a593Smuzhiyun #include <spi.h>
25*4882a593Smuzhiyun #include <linux/errno.h>
26*4882a593Smuzhiyun #include <asm/io.h>
27*4882a593Smuzhiyun #include <asm-generic/gpio.h>
28*4882a593Smuzhiyun #include <dm/device-internal.h>
29*4882a593Smuzhiyun #include <dm/of_extra.h>
30*4882a593Smuzhiyun #include <dm/uclass-internal.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #ifdef DEBUG_TRACE
33*4882a593Smuzhiyun #define debug_trace(fmt, b...) debug(fmt, #b)
34*4882a593Smuzhiyun #else
35*4882a593Smuzhiyun #define debug_trace(fmt, b...)
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun enum {
39*4882a593Smuzhiyun /* Timeout waiting for a flash erase command to complete */
40*4882a593Smuzhiyun CROS_EC_CMD_TIMEOUT_MS = 5000,
41*4882a593Smuzhiyun /* Timeout waiting for a synchronous hash to be recomputed */
42*4882a593Smuzhiyun CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
46*4882a593Smuzhiyun
cros_ec_dump_data(const char * name,int cmd,const uint8_t * data,int len)47*4882a593Smuzhiyun void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun #ifdef DEBUG
50*4882a593Smuzhiyun int i;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun printf("%s: ", name);
53*4882a593Smuzhiyun if (cmd != -1)
54*4882a593Smuzhiyun printf("cmd=%#x: ", cmd);
55*4882a593Smuzhiyun for (i = 0; i < len; i++)
56*4882a593Smuzhiyun printf("%02x ", data[i]);
57*4882a593Smuzhiyun printf("\n");
58*4882a593Smuzhiyun #endif
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun * Calculate a simple 8-bit checksum of a data block
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * @param data Data block to checksum
65*4882a593Smuzhiyun * @param size Size of data block in bytes
66*4882a593Smuzhiyun * @return checksum value (0 to 255)
67*4882a593Smuzhiyun */
cros_ec_calc_checksum(const uint8_t * data,int size)68*4882a593Smuzhiyun int cros_ec_calc_checksum(const uint8_t *data, int size)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun int csum, i;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun for (i = csum = 0; i < size; i++)
73*4882a593Smuzhiyun csum += data[i];
74*4882a593Smuzhiyun return csum & 0xff;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * Create a request packet for protocol version 3.
79*4882a593Smuzhiyun *
80*4882a593Smuzhiyun * The packet is stored in the device's internal output buffer.
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * @param dev CROS-EC device
83*4882a593Smuzhiyun * @param cmd Command to send (EC_CMD_...)
84*4882a593Smuzhiyun * @param cmd_version Version of command to send (EC_VER_...)
85*4882a593Smuzhiyun * @param dout Output data (may be NULL If dout_len=0)
86*4882a593Smuzhiyun * @param dout_len Size of output data in bytes
87*4882a593Smuzhiyun * @return packet size in bytes, or <0 if error.
88*4882a593Smuzhiyun */
create_proto3_request(struct cros_ec_dev * dev,int cmd,int cmd_version,const void * dout,int dout_len)89*4882a593Smuzhiyun static int create_proto3_request(struct cros_ec_dev *dev,
90*4882a593Smuzhiyun int cmd, int cmd_version,
91*4882a593Smuzhiyun const void *dout, int dout_len)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun struct ec_host_request *rq = (struct ec_host_request *)dev->dout;
94*4882a593Smuzhiyun int out_bytes = dout_len + sizeof(*rq);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* Fail if output size is too big */
97*4882a593Smuzhiyun if (out_bytes > (int)sizeof(dev->dout)) {
98*4882a593Smuzhiyun debug("%s: Cannot send %d bytes\n", __func__, dout_len);
99*4882a593Smuzhiyun return -EC_RES_REQUEST_TRUNCATED;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* Fill in request packet */
103*4882a593Smuzhiyun rq->struct_version = EC_HOST_REQUEST_VERSION;
104*4882a593Smuzhiyun rq->checksum = 0;
105*4882a593Smuzhiyun rq->command = cmd;
106*4882a593Smuzhiyun rq->command_version = cmd_version;
107*4882a593Smuzhiyun rq->reserved = 0;
108*4882a593Smuzhiyun rq->data_len = dout_len;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /* Copy data after header */
111*4882a593Smuzhiyun memcpy(rq + 1, dout, dout_len);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* Write checksum field so the entire packet sums to 0 */
114*4882a593Smuzhiyun rq->checksum = (uint8_t)(-cros_ec_calc_checksum(dev->dout, out_bytes));
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun cros_ec_dump_data("out", cmd, dev->dout, out_bytes);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /* Return size of request packet */
119*4882a593Smuzhiyun return out_bytes;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /**
123*4882a593Smuzhiyun * Prepare the device to receive a protocol version 3 response.
124*4882a593Smuzhiyun *
125*4882a593Smuzhiyun * @param dev CROS-EC device
126*4882a593Smuzhiyun * @param din_len Maximum size of response in bytes
127*4882a593Smuzhiyun * @return maximum expected number of bytes in response, or <0 if error.
128*4882a593Smuzhiyun */
prepare_proto3_response_buffer(struct cros_ec_dev * dev,int din_len)129*4882a593Smuzhiyun static int prepare_proto3_response_buffer(struct cros_ec_dev *dev, int din_len)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun int in_bytes = din_len + sizeof(struct ec_host_response);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Fail if input size is too big */
134*4882a593Smuzhiyun if (in_bytes > (int)sizeof(dev->din)) {
135*4882a593Smuzhiyun debug("%s: Cannot receive %d bytes\n", __func__, din_len);
136*4882a593Smuzhiyun return -EC_RES_RESPONSE_TOO_BIG;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Return expected size of response packet */
140*4882a593Smuzhiyun return in_bytes;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /**
144*4882a593Smuzhiyun * Handle a protocol version 3 response packet.
145*4882a593Smuzhiyun *
146*4882a593Smuzhiyun * The packet must already be stored in the device's internal input buffer.
147*4882a593Smuzhiyun *
148*4882a593Smuzhiyun * @param dev CROS-EC device
149*4882a593Smuzhiyun * @param dinp Returns pointer to response data
150*4882a593Smuzhiyun * @param din_len Maximum size of response in bytes
151*4882a593Smuzhiyun * @return number of bytes of response data, or <0 if error. Note that error
152*4882a593Smuzhiyun * codes can be from errno.h or -ve EC_RES_INVALID_CHECKSUM values (and they
153*4882a593Smuzhiyun * overlap!)
154*4882a593Smuzhiyun */
handle_proto3_response(struct cros_ec_dev * dev,uint8_t ** dinp,int din_len)155*4882a593Smuzhiyun static int handle_proto3_response(struct cros_ec_dev *dev,
156*4882a593Smuzhiyun uint8_t **dinp, int din_len)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun struct ec_host_response *rs = (struct ec_host_response *)dev->din;
159*4882a593Smuzhiyun int in_bytes;
160*4882a593Smuzhiyun int csum;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun cros_ec_dump_data("in-header", -1, dev->din, sizeof(*rs));
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* Check input data */
165*4882a593Smuzhiyun if (rs->struct_version != EC_HOST_RESPONSE_VERSION) {
166*4882a593Smuzhiyun debug("%s: EC response version mismatch\n", __func__);
167*4882a593Smuzhiyun return -EC_RES_INVALID_RESPONSE;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (rs->reserved) {
171*4882a593Smuzhiyun debug("%s: EC response reserved != 0\n", __func__);
172*4882a593Smuzhiyun return -EC_RES_INVALID_RESPONSE;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (rs->data_len > din_len) {
176*4882a593Smuzhiyun debug("%s: EC returned too much data\n", __func__);
177*4882a593Smuzhiyun return -EC_RES_RESPONSE_TOO_BIG;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun cros_ec_dump_data("in-data", -1, dev->din + sizeof(*rs), rs->data_len);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Update in_bytes to actual data size */
183*4882a593Smuzhiyun in_bytes = sizeof(*rs) + rs->data_len;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /* Verify checksum */
186*4882a593Smuzhiyun csum = cros_ec_calc_checksum(dev->din, in_bytes);
187*4882a593Smuzhiyun if (csum) {
188*4882a593Smuzhiyun debug("%s: EC response checksum invalid: 0x%02x\n", __func__,
189*4882a593Smuzhiyun csum);
190*4882a593Smuzhiyun return -EC_RES_INVALID_CHECKSUM;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* Return error result, if any */
194*4882a593Smuzhiyun if (rs->result)
195*4882a593Smuzhiyun return -(int)rs->result;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* If we're still here, set response data pointer and return length */
198*4882a593Smuzhiyun *dinp = (uint8_t *)(rs + 1);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun return rs->data_len;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
send_command_proto3(struct cros_ec_dev * dev,int cmd,int cmd_version,const void * dout,int dout_len,uint8_t ** dinp,int din_len)203*4882a593Smuzhiyun static int send_command_proto3(struct cros_ec_dev *dev,
204*4882a593Smuzhiyun int cmd, int cmd_version,
205*4882a593Smuzhiyun const void *dout, int dout_len,
206*4882a593Smuzhiyun uint8_t **dinp, int din_len)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun struct dm_cros_ec_ops *ops;
209*4882a593Smuzhiyun int out_bytes, in_bytes;
210*4882a593Smuzhiyun int rv;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /* Create request packet */
213*4882a593Smuzhiyun out_bytes = create_proto3_request(dev, cmd, cmd_version,
214*4882a593Smuzhiyun dout, dout_len);
215*4882a593Smuzhiyun if (out_bytes < 0)
216*4882a593Smuzhiyun return out_bytes;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* Prepare response buffer */
219*4882a593Smuzhiyun in_bytes = prepare_proto3_response_buffer(dev, din_len);
220*4882a593Smuzhiyun if (in_bytes < 0)
221*4882a593Smuzhiyun return in_bytes;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun ops = dm_cros_ec_get_ops(dev->dev);
224*4882a593Smuzhiyun rv = ops->packet ? ops->packet(dev->dev, out_bytes, in_bytes) : -ENOSYS;
225*4882a593Smuzhiyun if (rv < 0)
226*4882a593Smuzhiyun return rv;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* Process the response */
229*4882a593Smuzhiyun return handle_proto3_response(dev, dinp, din_len);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
send_command(struct cros_ec_dev * dev,uint8_t cmd,int cmd_version,const void * dout,int dout_len,uint8_t ** dinp,int din_len)232*4882a593Smuzhiyun static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
233*4882a593Smuzhiyun const void *dout, int dout_len,
234*4882a593Smuzhiyun uint8_t **dinp, int din_len)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct dm_cros_ec_ops *ops;
237*4882a593Smuzhiyun int ret = -1;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* Handle protocol version 3 support */
240*4882a593Smuzhiyun if (dev->protocol_version == 3) {
241*4882a593Smuzhiyun return send_command_proto3(dev, cmd, cmd_version,
242*4882a593Smuzhiyun dout, dout_len, dinp, din_len);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun ops = dm_cros_ec_get_ops(dev->dev);
246*4882a593Smuzhiyun ret = ops->command(dev->dev, cmd, cmd_version,
247*4882a593Smuzhiyun (const uint8_t *)dout, dout_len, dinp, din_len);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun return ret;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /**
253*4882a593Smuzhiyun * Send a command to the CROS-EC device and return the reply.
254*4882a593Smuzhiyun *
255*4882a593Smuzhiyun * The device's internal input/output buffers are used.
256*4882a593Smuzhiyun *
257*4882a593Smuzhiyun * @param dev CROS-EC device
258*4882a593Smuzhiyun * @param cmd Command to send (EC_CMD_...)
259*4882a593Smuzhiyun * @param cmd_version Version of command to send (EC_VER_...)
260*4882a593Smuzhiyun * @param dout Output data (may be NULL If dout_len=0)
261*4882a593Smuzhiyun * @param dout_len Size of output data in bytes
262*4882a593Smuzhiyun * @param dinp Response data (may be NULL If din_len=0).
263*4882a593Smuzhiyun * If not NULL, it will be updated to point to the data
264*4882a593Smuzhiyun * and will always be double word aligned (64-bits)
265*4882a593Smuzhiyun * @param din_len Maximum size of response in bytes
266*4882a593Smuzhiyun * @return number of bytes in response, or -ve on error
267*4882a593Smuzhiyun */
ec_command_inptr(struct cros_ec_dev * dev,uint8_t cmd,int cmd_version,const void * dout,int dout_len,uint8_t ** dinp,int din_len)268*4882a593Smuzhiyun static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
269*4882a593Smuzhiyun int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
270*4882a593Smuzhiyun int din_len)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun uint8_t *din = NULL;
273*4882a593Smuzhiyun int len;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun len = send_command(dev, cmd, cmd_version, dout, dout_len,
276*4882a593Smuzhiyun &din, din_len);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* If the command doesn't complete, wait a while */
279*4882a593Smuzhiyun if (len == -EC_RES_IN_PROGRESS) {
280*4882a593Smuzhiyun struct ec_response_get_comms_status *resp = NULL;
281*4882a593Smuzhiyun ulong start;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /* Wait for command to complete */
284*4882a593Smuzhiyun start = get_timer(0);
285*4882a593Smuzhiyun do {
286*4882a593Smuzhiyun int ret;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun mdelay(50); /* Insert some reasonable delay */
289*4882a593Smuzhiyun ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0,
290*4882a593Smuzhiyun NULL, 0,
291*4882a593Smuzhiyun (uint8_t **)&resp, sizeof(*resp));
292*4882a593Smuzhiyun if (ret < 0)
293*4882a593Smuzhiyun return ret;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) {
296*4882a593Smuzhiyun debug("%s: Command %#02x timeout\n",
297*4882a593Smuzhiyun __func__, cmd);
298*4882a593Smuzhiyun return -EC_RES_TIMEOUT;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun } while (resp->flags & EC_COMMS_STATUS_PROCESSING);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* OK it completed, so read the status response */
303*4882a593Smuzhiyun /* not sure why it was 0 for the last argument */
304*4882a593Smuzhiyun len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0,
305*4882a593Smuzhiyun NULL, 0, &din, din_len);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun debug("%s: len=%d, din=%p\n", __func__, len, din);
309*4882a593Smuzhiyun if (dinp) {
310*4882a593Smuzhiyun /* If we have any data to return, it must be 64bit-aligned */
311*4882a593Smuzhiyun assert(len <= 0 || !((uintptr_t)din & 7));
312*4882a593Smuzhiyun *dinp = din;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return len;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /**
319*4882a593Smuzhiyun * Send a command to the CROS-EC device and return the reply.
320*4882a593Smuzhiyun *
321*4882a593Smuzhiyun * The device's internal input/output buffers are used.
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun * @param dev CROS-EC device
324*4882a593Smuzhiyun * @param cmd Command to send (EC_CMD_...)
325*4882a593Smuzhiyun * @param cmd_version Version of command to send (EC_VER_...)
326*4882a593Smuzhiyun * @param dout Output data (may be NULL If dout_len=0)
327*4882a593Smuzhiyun * @param dout_len Size of output data in bytes
328*4882a593Smuzhiyun * @param din Response data (may be NULL If din_len=0).
329*4882a593Smuzhiyun * It not NULL, it is a place for ec_command() to copy the
330*4882a593Smuzhiyun * data to.
331*4882a593Smuzhiyun * @param din_len Maximum size of response in bytes
332*4882a593Smuzhiyun * @return number of bytes in response, or -ve on error
333*4882a593Smuzhiyun */
ec_command(struct cros_ec_dev * dev,uint8_t cmd,int cmd_version,const void * dout,int dout_len,void * din,int din_len)334*4882a593Smuzhiyun static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
335*4882a593Smuzhiyun const void *dout, int dout_len,
336*4882a593Smuzhiyun void *din, int din_len)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun uint8_t *in_buffer;
339*4882a593Smuzhiyun int len;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun assert((din_len == 0) || din);
342*4882a593Smuzhiyun len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len,
343*4882a593Smuzhiyun &in_buffer, din_len);
344*4882a593Smuzhiyun if (len > 0) {
345*4882a593Smuzhiyun /*
346*4882a593Smuzhiyun * If we were asked to put it somewhere, do so, otherwise just
347*4882a593Smuzhiyun * disregard the result.
348*4882a593Smuzhiyun */
349*4882a593Smuzhiyun if (din && in_buffer) {
350*4882a593Smuzhiyun assert(len <= din_len);
351*4882a593Smuzhiyun memmove(din, in_buffer, len);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun return len;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
cros_ec_scan_keyboard(struct udevice * dev,struct mbkp_keyscan * scan)357*4882a593Smuzhiyun int cros_ec_scan_keyboard(struct udevice *dev, struct mbkp_keyscan *scan)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (ec_command(cdev, EC_CMD_MKBP_STATE, 0, NULL, 0, scan,
362*4882a593Smuzhiyun sizeof(scan->data)) != sizeof(scan->data))
363*4882a593Smuzhiyun return -1;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun return 0;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
cros_ec_read_id(struct cros_ec_dev * dev,char * id,int maxlen)368*4882a593Smuzhiyun int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun struct ec_response_get_version *r;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
373*4882a593Smuzhiyun (uint8_t **)&r, sizeof(*r)) != sizeof(*r))
374*4882a593Smuzhiyun return -1;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun if (maxlen > (int)sizeof(r->version_string_ro))
377*4882a593Smuzhiyun maxlen = sizeof(r->version_string_ro);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun switch (r->current_image) {
380*4882a593Smuzhiyun case EC_IMAGE_RO:
381*4882a593Smuzhiyun memcpy(id, r->version_string_ro, maxlen);
382*4882a593Smuzhiyun break;
383*4882a593Smuzhiyun case EC_IMAGE_RW:
384*4882a593Smuzhiyun memcpy(id, r->version_string_rw, maxlen);
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun default:
387*4882a593Smuzhiyun return -1;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun id[maxlen - 1] = '\0';
391*4882a593Smuzhiyun return 0;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
cros_ec_read_version(struct cros_ec_dev * dev,struct ec_response_get_version ** versionp)394*4882a593Smuzhiyun int cros_ec_read_version(struct cros_ec_dev *dev,
395*4882a593Smuzhiyun struct ec_response_get_version **versionp)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
398*4882a593Smuzhiyun (uint8_t **)versionp, sizeof(**versionp))
399*4882a593Smuzhiyun != sizeof(**versionp))
400*4882a593Smuzhiyun return -1;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
cros_ec_read_build_info(struct cros_ec_dev * dev,char ** strp)405*4882a593Smuzhiyun int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0,
408*4882a593Smuzhiyun (uint8_t **)strp, EC_PROTO2_MAX_PARAM_SIZE) < 0)
409*4882a593Smuzhiyun return -1;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun return 0;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
cros_ec_read_current_image(struct cros_ec_dev * dev,enum ec_current_image * image)414*4882a593Smuzhiyun int cros_ec_read_current_image(struct cros_ec_dev *dev,
415*4882a593Smuzhiyun enum ec_current_image *image)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun struct ec_response_get_version *r;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
420*4882a593Smuzhiyun (uint8_t **)&r, sizeof(*r)) != sizeof(*r))
421*4882a593Smuzhiyun return -1;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun *image = r->current_image;
424*4882a593Smuzhiyun return 0;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
cros_ec_wait_on_hash_done(struct cros_ec_dev * dev,struct ec_response_vboot_hash * hash)427*4882a593Smuzhiyun static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev,
428*4882a593Smuzhiyun struct ec_response_vboot_hash *hash)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun struct ec_params_vboot_hash p;
431*4882a593Smuzhiyun ulong start;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun start = get_timer(0);
434*4882a593Smuzhiyun while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
435*4882a593Smuzhiyun mdelay(50); /* Insert some reasonable delay */
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun p.cmd = EC_VBOOT_HASH_GET;
438*4882a593Smuzhiyun if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
439*4882a593Smuzhiyun hash, sizeof(*hash)) < 0)
440*4882a593Smuzhiyun return -1;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) {
443*4882a593Smuzhiyun debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__);
444*4882a593Smuzhiyun return -EC_RES_TIMEOUT;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun return 0;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun
cros_ec_read_hash(struct cros_ec_dev * dev,struct ec_response_vboot_hash * hash)451*4882a593Smuzhiyun int cros_ec_read_hash(struct cros_ec_dev *dev,
452*4882a593Smuzhiyun struct ec_response_vboot_hash *hash)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun struct ec_params_vboot_hash p;
455*4882a593Smuzhiyun int rv;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun p.cmd = EC_VBOOT_HASH_GET;
458*4882a593Smuzhiyun if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
459*4882a593Smuzhiyun hash, sizeof(*hash)) < 0)
460*4882a593Smuzhiyun return -1;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /* If the EC is busy calculating the hash, fidget until it's done. */
463*4882a593Smuzhiyun rv = cros_ec_wait_on_hash_done(dev, hash);
464*4882a593Smuzhiyun if (rv)
465*4882a593Smuzhiyun return rv;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /* If the hash is valid, we're done. Otherwise, we have to kick it off
468*4882a593Smuzhiyun * again and wait for it to complete. Note that we explicitly assume
469*4882a593Smuzhiyun * that hashing zero bytes is always wrong, even though that would
470*4882a593Smuzhiyun * produce a valid hash value. */
471*4882a593Smuzhiyun if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size)
472*4882a593Smuzhiyun return 0;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun debug("%s: No valid hash (status=%d size=%d). Compute one...\n",
475*4882a593Smuzhiyun __func__, hash->status, hash->size);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun p.cmd = EC_VBOOT_HASH_START;
478*4882a593Smuzhiyun p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
479*4882a593Smuzhiyun p.nonce_size = 0;
480*4882a593Smuzhiyun p.offset = EC_VBOOT_HASH_OFFSET_RW;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
483*4882a593Smuzhiyun hash, sizeof(*hash)) < 0)
484*4882a593Smuzhiyun return -1;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun rv = cros_ec_wait_on_hash_done(dev, hash);
487*4882a593Smuzhiyun if (rv)
488*4882a593Smuzhiyun return rv;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun debug("%s: hash done\n", __func__);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
cros_ec_invalidate_hash(struct cros_ec_dev * dev)495*4882a593Smuzhiyun static int cros_ec_invalidate_hash(struct cros_ec_dev *dev)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun struct ec_params_vboot_hash p;
498*4882a593Smuzhiyun struct ec_response_vboot_hash *hash;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun /* We don't have an explict command for the EC to discard its current
501*4882a593Smuzhiyun * hash value, so we'll just tell it to calculate one that we know is
502*4882a593Smuzhiyun * wrong (we claim that hashing zero bytes is always invalid).
503*4882a593Smuzhiyun */
504*4882a593Smuzhiyun p.cmd = EC_VBOOT_HASH_RECALC;
505*4882a593Smuzhiyun p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
506*4882a593Smuzhiyun p.nonce_size = 0;
507*4882a593Smuzhiyun p.offset = 0;
508*4882a593Smuzhiyun p.size = 0;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun debug("%s:\n", __func__);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
513*4882a593Smuzhiyun (uint8_t **)&hash, sizeof(*hash)) < 0)
514*4882a593Smuzhiyun return -1;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /* No need to wait for it to finish */
517*4882a593Smuzhiyun return 0;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
cros_ec_reboot(struct cros_ec_dev * dev,enum ec_reboot_cmd cmd,uint8_t flags)520*4882a593Smuzhiyun int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
521*4882a593Smuzhiyun uint8_t flags)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun struct ec_params_reboot_ec p;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun p.cmd = cmd;
526*4882a593Smuzhiyun p.flags = flags;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0)
529*4882a593Smuzhiyun < 0)
530*4882a593Smuzhiyun return -1;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
533*4882a593Smuzhiyun /*
534*4882a593Smuzhiyun * EC reboot will take place immediately so delay to allow it
535*4882a593Smuzhiyun * to complete. Note that some reboot types (EC_REBOOT_COLD)
536*4882a593Smuzhiyun * will reboot the AP as well, in which case we won't actually
537*4882a593Smuzhiyun * get to this point.
538*4882a593Smuzhiyun */
539*4882a593Smuzhiyun /*
540*4882a593Smuzhiyun * TODO(rspangler@chromium.org): Would be nice if we had a
541*4882a593Smuzhiyun * better way to determine when the reboot is complete. Could
542*4882a593Smuzhiyun * we poll a memory-mapped LPC value?
543*4882a593Smuzhiyun */
544*4882a593Smuzhiyun udelay(50000);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun return 0;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
cros_ec_interrupt_pending(struct udevice * dev)550*4882a593Smuzhiyun int cros_ec_interrupt_pending(struct udevice *dev)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /* no interrupt support : always poll */
555*4882a593Smuzhiyun if (!dm_gpio_is_valid(&cdev->ec_int))
556*4882a593Smuzhiyun return -ENOENT;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun return dm_gpio_get_value(&cdev->ec_int);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
cros_ec_info(struct cros_ec_dev * dev,struct ec_response_mkbp_info * info)561*4882a593Smuzhiyun int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_mkbp_info *info)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun if (ec_command(dev, EC_CMD_MKBP_INFO, 0, NULL, 0, info,
564*4882a593Smuzhiyun sizeof(*info)) != sizeof(*info))
565*4882a593Smuzhiyun return -1;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun return 0;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
cros_ec_get_host_events(struct cros_ec_dev * dev,uint32_t * events_ptr)570*4882a593Smuzhiyun int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun struct ec_response_host_event_mask *resp;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /*
575*4882a593Smuzhiyun * Use the B copy of the event flags, because the main copy is already
576*4882a593Smuzhiyun * used by ACPI/SMI.
577*4882a593Smuzhiyun */
578*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0,
579*4882a593Smuzhiyun (uint8_t **)&resp, sizeof(*resp)) < (int)sizeof(*resp))
580*4882a593Smuzhiyun return -1;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID))
583*4882a593Smuzhiyun return -1;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun *events_ptr = resp->mask;
586*4882a593Smuzhiyun return 0;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun
cros_ec_clear_host_events(struct cros_ec_dev * dev,uint32_t events)589*4882a593Smuzhiyun int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun struct ec_params_host_event_mask params;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun params.mask = events;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun /*
596*4882a593Smuzhiyun * Use the B copy of the event flags, so it affects the data returned
597*4882a593Smuzhiyun * by cros_ec_get_host_events().
598*4882a593Smuzhiyun */
599*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0,
600*4882a593Smuzhiyun ¶ms, sizeof(params), NULL, 0) < 0)
601*4882a593Smuzhiyun return -1;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun return 0;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
cros_ec_flash_protect(struct cros_ec_dev * dev,uint32_t set_mask,uint32_t set_flags,struct ec_response_flash_protect * resp)606*4882a593Smuzhiyun int cros_ec_flash_protect(struct cros_ec_dev *dev,
607*4882a593Smuzhiyun uint32_t set_mask, uint32_t set_flags,
608*4882a593Smuzhiyun struct ec_response_flash_protect *resp)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun struct ec_params_flash_protect params;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun params.mask = set_mask;
613*4882a593Smuzhiyun params.flags = set_flags;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
616*4882a593Smuzhiyun ¶ms, sizeof(params),
617*4882a593Smuzhiyun resp, sizeof(*resp)) != sizeof(*resp))
618*4882a593Smuzhiyun return -1;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun return 0;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
cros_ec_check_version(struct cros_ec_dev * dev)623*4882a593Smuzhiyun static int cros_ec_check_version(struct cros_ec_dev *dev)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun struct ec_params_hello req;
626*4882a593Smuzhiyun struct ec_response_hello *resp;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun struct dm_cros_ec_ops *ops;
629*4882a593Smuzhiyun int ret;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun ops = dm_cros_ec_get_ops(dev->dev);
632*4882a593Smuzhiyun if (ops->check_version) {
633*4882a593Smuzhiyun ret = ops->check_version(dev->dev);
634*4882a593Smuzhiyun if (ret)
635*4882a593Smuzhiyun return ret;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun /*
639*4882a593Smuzhiyun * TODO(sjg@chromium.org).
640*4882a593Smuzhiyun * There is a strange oddity here with the EC. We could just ignore
641*4882a593Smuzhiyun * the response, i.e. pass the last two parameters as NULL and 0.
642*4882a593Smuzhiyun * In this case we won't read back very many bytes from the EC.
643*4882a593Smuzhiyun * On the I2C bus the EC gets upset about this and will try to send
644*4882a593Smuzhiyun * the bytes anyway. This means that we will have to wait for that
645*4882a593Smuzhiyun * to complete before continuing with a new EC command.
646*4882a593Smuzhiyun *
647*4882a593Smuzhiyun * This problem is probably unique to the I2C bus.
648*4882a593Smuzhiyun *
649*4882a593Smuzhiyun * So for now, just read all the data anyway.
650*4882a593Smuzhiyun */
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun /* Try sending a version 3 packet */
653*4882a593Smuzhiyun dev->protocol_version = 3;
654*4882a593Smuzhiyun req.in_data = 0;
655*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
656*4882a593Smuzhiyun (uint8_t **)&resp, sizeof(*resp)) > 0) {
657*4882a593Smuzhiyun return 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun /* Try sending a version 2 packet */
661*4882a593Smuzhiyun dev->protocol_version = 2;
662*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
663*4882a593Smuzhiyun (uint8_t **)&resp, sizeof(*resp)) > 0) {
664*4882a593Smuzhiyun return 0;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun /*
668*4882a593Smuzhiyun * Fail if we're still here, since the EC doesn't understand any
669*4882a593Smuzhiyun * protcol version we speak. Version 1 interface without command
670*4882a593Smuzhiyun * version is no longer supported, and we don't know about any new
671*4882a593Smuzhiyun * protocol versions.
672*4882a593Smuzhiyun */
673*4882a593Smuzhiyun dev->protocol_version = 0;
674*4882a593Smuzhiyun printf("%s: ERROR: old EC interface not supported\n", __func__);
675*4882a593Smuzhiyun return -1;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
cros_ec_test(struct cros_ec_dev * dev)678*4882a593Smuzhiyun int cros_ec_test(struct cros_ec_dev *dev)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun struct ec_params_hello req;
681*4882a593Smuzhiyun struct ec_response_hello *resp;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun req.in_data = 0x12345678;
684*4882a593Smuzhiyun if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
685*4882a593Smuzhiyun (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
686*4882a593Smuzhiyun printf("ec_command_inptr() returned error\n");
687*4882a593Smuzhiyun return -1;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun if (resp->out_data != req.in_data + 0x01020304) {
690*4882a593Smuzhiyun printf("Received invalid handshake %x\n", resp->out_data);
691*4882a593Smuzhiyun return -1;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun return 0;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun
cros_ec_flash_offset(struct cros_ec_dev * dev,enum ec_flash_region region,uint32_t * offset,uint32_t * size)697*4882a593Smuzhiyun int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
698*4882a593Smuzhiyun uint32_t *offset, uint32_t *size)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun struct ec_params_flash_region_info p;
701*4882a593Smuzhiyun struct ec_response_flash_region_info *r;
702*4882a593Smuzhiyun int ret;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun p.region = region;
705*4882a593Smuzhiyun ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO,
706*4882a593Smuzhiyun EC_VER_FLASH_REGION_INFO,
707*4882a593Smuzhiyun &p, sizeof(p), (uint8_t **)&r, sizeof(*r));
708*4882a593Smuzhiyun if (ret != sizeof(*r))
709*4882a593Smuzhiyun return -1;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun if (offset)
712*4882a593Smuzhiyun *offset = r->offset;
713*4882a593Smuzhiyun if (size)
714*4882a593Smuzhiyun *size = r->size;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun return 0;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
cros_ec_flash_erase(struct cros_ec_dev * dev,uint32_t offset,uint32_t size)719*4882a593Smuzhiyun int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
720*4882a593Smuzhiyun {
721*4882a593Smuzhiyun struct ec_params_flash_erase p;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun p.offset = offset;
724*4882a593Smuzhiyun p.size = size;
725*4882a593Smuzhiyun return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p),
726*4882a593Smuzhiyun NULL, 0);
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun /**
730*4882a593Smuzhiyun * Write a single block to the flash
731*4882a593Smuzhiyun *
732*4882a593Smuzhiyun * Write a block of data to the EC flash. The size must not exceed the flash
733*4882a593Smuzhiyun * write block size which you can obtain from cros_ec_flash_write_burst_size().
734*4882a593Smuzhiyun *
735*4882a593Smuzhiyun * The offset starts at 0. You can obtain the region information from
736*4882a593Smuzhiyun * cros_ec_flash_offset() to find out where to write for a particular region.
737*4882a593Smuzhiyun *
738*4882a593Smuzhiyun * Attempting to write to the region where the EC is currently running from
739*4882a593Smuzhiyun * will result in an error.
740*4882a593Smuzhiyun *
741*4882a593Smuzhiyun * @param dev CROS-EC device
742*4882a593Smuzhiyun * @param data Pointer to data buffer to write
743*4882a593Smuzhiyun * @param offset Offset within flash to write to.
744*4882a593Smuzhiyun * @param size Number of bytes to write
745*4882a593Smuzhiyun * @return 0 if ok, -1 on error
746*4882a593Smuzhiyun */
cros_ec_flash_write_block(struct cros_ec_dev * dev,const uint8_t * data,uint32_t offset,uint32_t size)747*4882a593Smuzhiyun static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
748*4882a593Smuzhiyun const uint8_t *data, uint32_t offset, uint32_t size)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun struct ec_params_flash_write *p;
751*4882a593Smuzhiyun int ret;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun p = malloc(sizeof(*p) + size);
754*4882a593Smuzhiyun if (!p)
755*4882a593Smuzhiyun return -ENOMEM;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun p->offset = offset;
758*4882a593Smuzhiyun p->size = size;
759*4882a593Smuzhiyun assert(data && p->size <= EC_FLASH_WRITE_VER0_SIZE);
760*4882a593Smuzhiyun memcpy(p + 1, data, p->size);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun ret = ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
763*4882a593Smuzhiyun p, sizeof(*p) + size, NULL, 0) >= 0 ? 0 : -1;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun free(p);
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun return ret;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun /**
771*4882a593Smuzhiyun * Return optimal flash write burst size
772*4882a593Smuzhiyun */
cros_ec_flash_write_burst_size(struct cros_ec_dev * dev)773*4882a593Smuzhiyun static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun return EC_FLASH_WRITE_VER0_SIZE;
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun /**
779*4882a593Smuzhiyun * Check if a block of data is erased (all 0xff)
780*4882a593Smuzhiyun *
781*4882a593Smuzhiyun * This function is useful when dealing with flash, for checking whether a
782*4882a593Smuzhiyun * data block is erased and thus does not need to be programmed.
783*4882a593Smuzhiyun *
784*4882a593Smuzhiyun * @param data Pointer to data to check (must be word-aligned)
785*4882a593Smuzhiyun * @param size Number of bytes to check (must be word-aligned)
786*4882a593Smuzhiyun * @return 0 if erased, non-zero if any word is not erased
787*4882a593Smuzhiyun */
cros_ec_data_is_erased(const uint32_t * data,int size)788*4882a593Smuzhiyun static int cros_ec_data_is_erased(const uint32_t *data, int size)
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun assert(!(size & 3));
791*4882a593Smuzhiyun size /= sizeof(uint32_t);
792*4882a593Smuzhiyun for (; size > 0; size -= 4, data++)
793*4882a593Smuzhiyun if (*data != -1U)
794*4882a593Smuzhiyun return 0;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun return 1;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun /**
800*4882a593Smuzhiyun * Read back flash parameters
801*4882a593Smuzhiyun *
802*4882a593Smuzhiyun * This function reads back parameters of the flash as reported by the EC
803*4882a593Smuzhiyun *
804*4882a593Smuzhiyun * @param dev Pointer to device
805*4882a593Smuzhiyun * @param info Pointer to output flash info struct
806*4882a593Smuzhiyun */
cros_ec_read_flashinfo(struct cros_ec_dev * dev,struct ec_response_flash_info * info)807*4882a593Smuzhiyun int cros_ec_read_flashinfo(struct cros_ec_dev *dev,
808*4882a593Smuzhiyun struct ec_response_flash_info *info)
809*4882a593Smuzhiyun {
810*4882a593Smuzhiyun int ret;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun ret = ec_command(dev, EC_CMD_FLASH_INFO, 0,
813*4882a593Smuzhiyun NULL, 0, info, sizeof(*info));
814*4882a593Smuzhiyun if (ret < 0)
815*4882a593Smuzhiyun return ret;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun return ret < sizeof(*info) ? -1 : 0;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
cros_ec_flash_write(struct cros_ec_dev * dev,const uint8_t * data,uint32_t offset,uint32_t size)820*4882a593Smuzhiyun int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
821*4882a593Smuzhiyun uint32_t offset, uint32_t size)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun uint32_t burst = cros_ec_flash_write_burst_size(dev);
824*4882a593Smuzhiyun uint32_t end, off;
825*4882a593Smuzhiyun int ret;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun /*
828*4882a593Smuzhiyun * TODO: round up to the nearest multiple of write size. Can get away
829*4882a593Smuzhiyun * without that on link right now because its write size is 4 bytes.
830*4882a593Smuzhiyun */
831*4882a593Smuzhiyun end = offset + size;
832*4882a593Smuzhiyun for (off = offset; off < end; off += burst, data += burst) {
833*4882a593Smuzhiyun uint32_t todo;
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun /* If the data is empty, there is no point in programming it */
836*4882a593Smuzhiyun todo = min(end - off, burst);
837*4882a593Smuzhiyun if (dev->optimise_flash_write &&
838*4882a593Smuzhiyun cros_ec_data_is_erased((uint32_t *)data, todo))
839*4882a593Smuzhiyun continue;
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun ret = cros_ec_flash_write_block(dev, data, off, todo);
842*4882a593Smuzhiyun if (ret)
843*4882a593Smuzhiyun return ret;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun return 0;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun /**
850*4882a593Smuzhiyun * Read a single block from the flash
851*4882a593Smuzhiyun *
852*4882a593Smuzhiyun * Read a block of data from the EC flash. The size must not exceed the flash
853*4882a593Smuzhiyun * write block size which you can obtain from cros_ec_flash_write_burst_size().
854*4882a593Smuzhiyun *
855*4882a593Smuzhiyun * The offset starts at 0. You can obtain the region information from
856*4882a593Smuzhiyun * cros_ec_flash_offset() to find out where to read for a particular region.
857*4882a593Smuzhiyun *
858*4882a593Smuzhiyun * @param dev CROS-EC device
859*4882a593Smuzhiyun * @param data Pointer to data buffer to read into
860*4882a593Smuzhiyun * @param offset Offset within flash to read from
861*4882a593Smuzhiyun * @param size Number of bytes to read
862*4882a593Smuzhiyun * @return 0 if ok, -1 on error
863*4882a593Smuzhiyun */
cros_ec_flash_read_block(struct cros_ec_dev * dev,uint8_t * data,uint32_t offset,uint32_t size)864*4882a593Smuzhiyun static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data,
865*4882a593Smuzhiyun uint32_t offset, uint32_t size)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun struct ec_params_flash_read p;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun p.offset = offset;
870*4882a593Smuzhiyun p.size = size;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun return ec_command(dev, EC_CMD_FLASH_READ, 0,
873*4882a593Smuzhiyun &p, sizeof(p), data, size) >= 0 ? 0 : -1;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
cros_ec_flash_read(struct cros_ec_dev * dev,uint8_t * data,uint32_t offset,uint32_t size)876*4882a593Smuzhiyun int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
877*4882a593Smuzhiyun uint32_t size)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun uint32_t burst = cros_ec_flash_write_burst_size(dev);
880*4882a593Smuzhiyun uint32_t end, off;
881*4882a593Smuzhiyun int ret;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun end = offset + size;
884*4882a593Smuzhiyun for (off = offset; off < end; off += burst, data += burst) {
885*4882a593Smuzhiyun ret = cros_ec_flash_read_block(dev, data, off,
886*4882a593Smuzhiyun min(end - off, burst));
887*4882a593Smuzhiyun if (ret)
888*4882a593Smuzhiyun return ret;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun return 0;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
cros_ec_flash_update_rw(struct cros_ec_dev * dev,const uint8_t * image,int image_size)894*4882a593Smuzhiyun int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
895*4882a593Smuzhiyun const uint8_t *image, int image_size)
896*4882a593Smuzhiyun {
897*4882a593Smuzhiyun uint32_t rw_offset, rw_size;
898*4882a593Smuzhiyun int ret;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size))
901*4882a593Smuzhiyun return -1;
902*4882a593Smuzhiyun if (image_size > (int)rw_size)
903*4882a593Smuzhiyun return -1;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun /* Invalidate the existing hash, just in case the AP reboots
906*4882a593Smuzhiyun * unexpectedly during the update. If that happened, the EC RW firmware
907*4882a593Smuzhiyun * would be invalid, but the EC would still have the original hash.
908*4882a593Smuzhiyun */
909*4882a593Smuzhiyun ret = cros_ec_invalidate_hash(dev);
910*4882a593Smuzhiyun if (ret)
911*4882a593Smuzhiyun return ret;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun /*
914*4882a593Smuzhiyun * Erase the entire RW section, so that the EC doesn't see any garbage
915*4882a593Smuzhiyun * past the new image if it's smaller than the current image.
916*4882a593Smuzhiyun *
917*4882a593Smuzhiyun * TODO: could optimize this to erase just the current image, since
918*4882a593Smuzhiyun * presumably everything past that is 0xff's. But would still need to
919*4882a593Smuzhiyun * round up to the nearest multiple of erase size.
920*4882a593Smuzhiyun */
921*4882a593Smuzhiyun ret = cros_ec_flash_erase(dev, rw_offset, rw_size);
922*4882a593Smuzhiyun if (ret)
923*4882a593Smuzhiyun return ret;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun /* Write the image */
926*4882a593Smuzhiyun ret = cros_ec_flash_write(dev, image, rw_offset, image_size);
927*4882a593Smuzhiyun if (ret)
928*4882a593Smuzhiyun return ret;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun return 0;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
cros_ec_read_vbnvcontext(struct cros_ec_dev * dev,uint8_t * block)933*4882a593Smuzhiyun int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun struct ec_params_vbnvcontext p;
936*4882a593Smuzhiyun int len;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun p.op = EC_VBNV_CONTEXT_OP_READ;
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
941*4882a593Smuzhiyun &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE);
942*4882a593Smuzhiyun if (len < EC_VBNV_BLOCK_SIZE)
943*4882a593Smuzhiyun return -1;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun return 0;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun
cros_ec_write_vbnvcontext(struct cros_ec_dev * dev,const uint8_t * block)948*4882a593Smuzhiyun int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun struct ec_params_vbnvcontext p;
951*4882a593Smuzhiyun int len;
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun p.op = EC_VBNV_CONTEXT_OP_WRITE;
954*4882a593Smuzhiyun memcpy(p.block, block, sizeof(p.block));
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
957*4882a593Smuzhiyun &p, sizeof(p), NULL, 0);
958*4882a593Smuzhiyun if (len < 0)
959*4882a593Smuzhiyun return -1;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun return 0;
962*4882a593Smuzhiyun }
963*4882a593Smuzhiyun
cros_ec_set_ldo(struct udevice * dev,uint8_t index,uint8_t state)964*4882a593Smuzhiyun int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state)
965*4882a593Smuzhiyun {
966*4882a593Smuzhiyun struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
967*4882a593Smuzhiyun struct ec_params_ldo_set params;
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun params.index = index;
970*4882a593Smuzhiyun params.state = state;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun if (ec_command_inptr(cdev, EC_CMD_LDO_SET, 0, ¶ms, sizeof(params),
973*4882a593Smuzhiyun NULL, 0))
974*4882a593Smuzhiyun return -1;
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun return 0;
977*4882a593Smuzhiyun }
978*4882a593Smuzhiyun
cros_ec_get_ldo(struct udevice * dev,uint8_t index,uint8_t * state)979*4882a593Smuzhiyun int cros_ec_get_ldo(struct udevice *dev, uint8_t index, uint8_t *state)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
982*4882a593Smuzhiyun struct ec_params_ldo_get params;
983*4882a593Smuzhiyun struct ec_response_ldo_get *resp;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun params.index = index;
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun if (ec_command_inptr(cdev, EC_CMD_LDO_GET, 0, ¶ms, sizeof(params),
988*4882a593Smuzhiyun (uint8_t **)&resp, sizeof(*resp)) !=
989*4882a593Smuzhiyun sizeof(*resp))
990*4882a593Smuzhiyun return -1;
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun *state = resp->state;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun return 0;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
cros_ec_register(struct udevice * dev)997*4882a593Smuzhiyun int cros_ec_register(struct udevice *dev)
998*4882a593Smuzhiyun {
999*4882a593Smuzhiyun struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
1000*4882a593Smuzhiyun char id[MSG_BYTES];
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun cdev->dev = dev;
1003*4882a593Smuzhiyun gpio_request_by_name(dev, "ec-interrupt", 0, &cdev->ec_int,
1004*4882a593Smuzhiyun GPIOD_IS_IN);
1005*4882a593Smuzhiyun cdev->optimise_flash_write = dev_read_bool(dev, "optimise-flash-write");
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun if (cros_ec_check_version(cdev)) {
1008*4882a593Smuzhiyun debug("%s: Could not detect CROS-EC version\n", __func__);
1009*4882a593Smuzhiyun return -CROS_EC_ERR_CHECK_VERSION;
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun if (cros_ec_read_id(cdev, id, sizeof(id))) {
1013*4882a593Smuzhiyun debug("%s: Could not read KBC ID\n", __func__);
1014*4882a593Smuzhiyun return -CROS_EC_ERR_READ_ID;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun /* Remember this device for use by the cros_ec command */
1018*4882a593Smuzhiyun debug("Google Chrome EC v%d CROS-EC driver ready, id '%s'\n",
1019*4882a593Smuzhiyun cdev->protocol_version, id);
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun return 0;
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
cros_ec_decode_ec_flash(struct udevice * dev,struct fdt_cros_ec * config)1024*4882a593Smuzhiyun int cros_ec_decode_ec_flash(struct udevice *dev, struct fdt_cros_ec *config)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun ofnode flash_node, node;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun flash_node = dev_read_subnode(dev, "flash");
1029*4882a593Smuzhiyun if (!ofnode_valid(flash_node)) {
1030*4882a593Smuzhiyun debug("Failed to find flash node\n");
1031*4882a593Smuzhiyun return -1;
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun if (of_read_fmap_entry(flash_node, "flash", &config->flash)) {
1035*4882a593Smuzhiyun debug("Failed to decode flash node in chrome-ec\n");
1036*4882a593Smuzhiyun return -1;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun config->flash_erase_value = ofnode_read_s32_default(flash_node,
1040*4882a593Smuzhiyun "erase-value", -1);
1041*4882a593Smuzhiyun ofnode_for_each_subnode(node, flash_node) {
1042*4882a593Smuzhiyun const char *name = ofnode_get_name(node);
1043*4882a593Smuzhiyun enum ec_flash_region region;
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun if (0 == strcmp(name, "ro")) {
1046*4882a593Smuzhiyun region = EC_FLASH_REGION_RO;
1047*4882a593Smuzhiyun } else if (0 == strcmp(name, "rw")) {
1048*4882a593Smuzhiyun region = EC_FLASH_REGION_RW;
1049*4882a593Smuzhiyun } else if (0 == strcmp(name, "wp-ro")) {
1050*4882a593Smuzhiyun region = EC_FLASH_REGION_WP_RO;
1051*4882a593Smuzhiyun } else {
1052*4882a593Smuzhiyun debug("Unknown EC flash region name '%s'\n", name);
1053*4882a593Smuzhiyun return -1;
1054*4882a593Smuzhiyun }
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun if (of_read_fmap_entry(node, "reg", &config->region[region])) {
1057*4882a593Smuzhiyun debug("Failed to decode flash region in chrome-ec'\n");
1058*4882a593Smuzhiyun return -1;
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun return 0;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun
cros_ec_i2c_tunnel(struct udevice * dev,int port,struct i2c_msg * in,int nmsgs)1065*4882a593Smuzhiyun int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in,
1066*4882a593Smuzhiyun int nmsgs)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
1069*4882a593Smuzhiyun union {
1070*4882a593Smuzhiyun struct ec_params_i2c_passthru p;
1071*4882a593Smuzhiyun uint8_t outbuf[EC_PROTO2_MAX_PARAM_SIZE];
1072*4882a593Smuzhiyun } params;
1073*4882a593Smuzhiyun union {
1074*4882a593Smuzhiyun struct ec_response_i2c_passthru r;
1075*4882a593Smuzhiyun uint8_t inbuf[EC_PROTO2_MAX_PARAM_SIZE];
1076*4882a593Smuzhiyun } response;
1077*4882a593Smuzhiyun struct ec_params_i2c_passthru *p = ¶ms.p;
1078*4882a593Smuzhiyun struct ec_response_i2c_passthru *r = &response.r;
1079*4882a593Smuzhiyun struct ec_params_i2c_passthru_msg *msg;
1080*4882a593Smuzhiyun uint8_t *pdata, *read_ptr = NULL;
1081*4882a593Smuzhiyun int read_len;
1082*4882a593Smuzhiyun int size;
1083*4882a593Smuzhiyun int rv;
1084*4882a593Smuzhiyun int i;
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun p->port = port;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun p->num_msgs = nmsgs;
1089*4882a593Smuzhiyun size = sizeof(*p) + p->num_msgs * sizeof(*msg);
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun /* Create a message to write the register address and optional data */
1092*4882a593Smuzhiyun pdata = (uint8_t *)p + size;
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun read_len = 0;
1095*4882a593Smuzhiyun for (i = 0, msg = p->msg; i < nmsgs; i++, msg++, in++) {
1096*4882a593Smuzhiyun bool is_read = in->flags & I2C_M_RD;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun msg->addr_flags = in->addr;
1099*4882a593Smuzhiyun msg->len = in->len;
1100*4882a593Smuzhiyun if (is_read) {
1101*4882a593Smuzhiyun msg->addr_flags |= EC_I2C_FLAG_READ;
1102*4882a593Smuzhiyun read_len += in->len;
1103*4882a593Smuzhiyun read_ptr = in->buf;
1104*4882a593Smuzhiyun if (sizeof(*r) + read_len > sizeof(response)) {
1105*4882a593Smuzhiyun puts("Read length too big for buffer\n");
1106*4882a593Smuzhiyun return -1;
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun } else {
1109*4882a593Smuzhiyun if (pdata - (uint8_t *)p + in->len > sizeof(params)) {
1110*4882a593Smuzhiyun puts("Params too large for buffer\n");
1111*4882a593Smuzhiyun return -1;
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun memcpy(pdata, in->buf, in->len);
1114*4882a593Smuzhiyun pdata += in->len;
1115*4882a593Smuzhiyun }
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun rv = ec_command(cdev, EC_CMD_I2C_PASSTHRU, 0, p, pdata - (uint8_t *)p,
1119*4882a593Smuzhiyun r, sizeof(*r) + read_len);
1120*4882a593Smuzhiyun if (rv < 0)
1121*4882a593Smuzhiyun return rv;
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun /* Parse response */
1124*4882a593Smuzhiyun if (r->i2c_status & EC_I2C_STATUS_ERROR) {
1125*4882a593Smuzhiyun printf("Transfer failed with status=0x%x\n", r->i2c_status);
1126*4882a593Smuzhiyun return -1;
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun if (rv < sizeof(*r) + read_len) {
1130*4882a593Smuzhiyun puts("Truncated read response\n");
1131*4882a593Smuzhiyun return -1;
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun /* We only support a single read message for each transfer */
1135*4882a593Smuzhiyun if (read_len)
1136*4882a593Smuzhiyun memcpy(read_ptr, r->data, read_len);
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun return 0;
1139*4882a593Smuzhiyun }
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun UCLASS_DRIVER(cros_ec) = {
1142*4882a593Smuzhiyun .id = UCLASS_CROS_EC,
1143*4882a593Smuzhiyun .name = "cros_ec",
1144*4882a593Smuzhiyun .per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
1145*4882a593Smuzhiyun .post_bind = dm_scan_fdt_dev,
1146*4882a593Smuzhiyun };
1147