xref: /rk3399_rockchip-uboot/drivers/misc/cros_ec.c (revision 88364387c60dc72549ccf7f2d595cbf847ab4e17)
1*88364387SHung-ying Tyan /*
2*88364387SHung-ying Tyan  * Chromium OS cros_ec driver
3*88364387SHung-ying Tyan  *
4*88364387SHung-ying Tyan  * Copyright (c) 2012 The Chromium OS Authors.
5*88364387SHung-ying Tyan  * See file CREDITS for list of people who contributed to this
6*88364387SHung-ying Tyan  * project.
7*88364387SHung-ying Tyan  *
8*88364387SHung-ying Tyan  * This program is free software; you can redistribute it and/or
9*88364387SHung-ying Tyan  * modify it under the terms of the GNU General Public License as
10*88364387SHung-ying Tyan  * published by the Free Software Foundation; either version 2 of
11*88364387SHung-ying Tyan  * the License, or (at your option) any later version.
12*88364387SHung-ying Tyan  *
13*88364387SHung-ying Tyan  * This program is distributed in the hope that it will be useful,
14*88364387SHung-ying Tyan  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*88364387SHung-ying Tyan  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*88364387SHung-ying Tyan  * GNU General Public License for more details.
17*88364387SHung-ying Tyan  *
18*88364387SHung-ying Tyan  * You should have received a copy of the GNU General Public License
19*88364387SHung-ying Tyan  * along with this program; if not, write to the Free Software
20*88364387SHung-ying Tyan  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21*88364387SHung-ying Tyan  * MA 02111-1307 USA
22*88364387SHung-ying Tyan  */
23*88364387SHung-ying Tyan 
24*88364387SHung-ying Tyan /*
25*88364387SHung-ying Tyan  * The Matrix Keyboard Protocol driver handles talking to the keyboard
26*88364387SHung-ying Tyan  * controller chip. Mostly this is for keyboard functions, but some other
27*88364387SHung-ying Tyan  * things have slipped in, so we provide generic services to talk to the
28*88364387SHung-ying Tyan  * KBC.
29*88364387SHung-ying Tyan  */
30*88364387SHung-ying Tyan 
31*88364387SHung-ying Tyan #include <common.h>
32*88364387SHung-ying Tyan #include <command.h>
33*88364387SHung-ying Tyan #include <i2c.h>
34*88364387SHung-ying Tyan #include <cros_ec.h>
35*88364387SHung-ying Tyan #include <fdtdec.h>
36*88364387SHung-ying Tyan #include <malloc.h>
37*88364387SHung-ying Tyan #include <spi.h>
38*88364387SHung-ying Tyan #include <asm/io.h>
39*88364387SHung-ying Tyan #include <asm-generic/gpio.h>
40*88364387SHung-ying Tyan 
41*88364387SHung-ying Tyan #ifdef DEBUG_TRACE
42*88364387SHung-ying Tyan #define debug_trace(fmt, b...)	debug(fmt, #b)
43*88364387SHung-ying Tyan #else
44*88364387SHung-ying Tyan #define debug_trace(fmt, b...)
45*88364387SHung-ying Tyan #endif
46*88364387SHung-ying Tyan 
47*88364387SHung-ying Tyan enum {
48*88364387SHung-ying Tyan 	/* Timeout waiting for a flash erase command to complete */
49*88364387SHung-ying Tyan 	CROS_EC_CMD_TIMEOUT_MS	= 5000,
50*88364387SHung-ying Tyan 	/* Timeout waiting for a synchronous hash to be recomputed */
51*88364387SHung-ying Tyan 	CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
52*88364387SHung-ying Tyan };
53*88364387SHung-ying Tyan 
54*88364387SHung-ying Tyan static struct cros_ec_dev static_dev, *last_dev;
55*88364387SHung-ying Tyan 
56*88364387SHung-ying Tyan DECLARE_GLOBAL_DATA_PTR;
57*88364387SHung-ying Tyan 
58*88364387SHung-ying Tyan /* Note: depends on enum ec_current_image */
59*88364387SHung-ying Tyan static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"};
60*88364387SHung-ying Tyan 
61*88364387SHung-ying Tyan void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len)
62*88364387SHung-ying Tyan {
63*88364387SHung-ying Tyan #ifdef DEBUG
64*88364387SHung-ying Tyan 	int i;
65*88364387SHung-ying Tyan 
66*88364387SHung-ying Tyan 	printf("%s: ", name);
67*88364387SHung-ying Tyan 	if (cmd != -1)
68*88364387SHung-ying Tyan 		printf("cmd=%#x: ", cmd);
69*88364387SHung-ying Tyan 	for (i = 0; i < len; i++)
70*88364387SHung-ying Tyan 		printf("%02x ", data[i]);
71*88364387SHung-ying Tyan 	printf("\n");
72*88364387SHung-ying Tyan #endif
73*88364387SHung-ying Tyan }
74*88364387SHung-ying Tyan 
75*88364387SHung-ying Tyan /*
76*88364387SHung-ying Tyan  * Calculate a simple 8-bit checksum of a data block
77*88364387SHung-ying Tyan  *
78*88364387SHung-ying Tyan  * @param data	Data block to checksum
79*88364387SHung-ying Tyan  * @param size	Size of data block in bytes
80*88364387SHung-ying Tyan  * @return checksum value (0 to 255)
81*88364387SHung-ying Tyan  */
82*88364387SHung-ying Tyan int cros_ec_calc_checksum(const uint8_t *data, int size)
83*88364387SHung-ying Tyan {
84*88364387SHung-ying Tyan 	int csum, i;
85*88364387SHung-ying Tyan 
86*88364387SHung-ying Tyan 	for (i = csum = 0; i < size; i++)
87*88364387SHung-ying Tyan 		csum += data[i];
88*88364387SHung-ying Tyan 	return csum & 0xff;
89*88364387SHung-ying Tyan }
90*88364387SHung-ying Tyan 
91*88364387SHung-ying Tyan static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
92*88364387SHung-ying Tyan 			const void *dout, int dout_len,
93*88364387SHung-ying Tyan 			uint8_t **dinp, int din_len)
94*88364387SHung-ying Tyan {
95*88364387SHung-ying Tyan 	int ret;
96*88364387SHung-ying Tyan 
97*88364387SHung-ying Tyan 	switch (dev->interface) {
98*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_SPI
99*88364387SHung-ying Tyan 	case CROS_EC_IF_SPI:
100*88364387SHung-ying Tyan 		ret = cros_ec_spi_command(dev, cmd, cmd_version,
101*88364387SHung-ying Tyan 					(const uint8_t *)dout, dout_len,
102*88364387SHung-ying Tyan 					dinp, din_len);
103*88364387SHung-ying Tyan 		break;
104*88364387SHung-ying Tyan #endif
105*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_I2C
106*88364387SHung-ying Tyan 	case CROS_EC_IF_I2C:
107*88364387SHung-ying Tyan 		ret = cros_ec_i2c_command(dev, cmd, cmd_version,
108*88364387SHung-ying Tyan 					(const uint8_t *)dout, dout_len,
109*88364387SHung-ying Tyan 					dinp, din_len);
110*88364387SHung-ying Tyan 		break;
111*88364387SHung-ying Tyan #endif
112*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC
113*88364387SHung-ying Tyan 	case CROS_EC_IF_LPC:
114*88364387SHung-ying Tyan 		ret = cros_ec_lpc_command(dev, cmd, cmd_version,
115*88364387SHung-ying Tyan 					(const uint8_t *)dout, dout_len,
116*88364387SHung-ying Tyan 					dinp, din_len);
117*88364387SHung-ying Tyan 		break;
118*88364387SHung-ying Tyan #endif
119*88364387SHung-ying Tyan 	case CROS_EC_IF_NONE:
120*88364387SHung-ying Tyan 	default:
121*88364387SHung-ying Tyan 		ret = -1;
122*88364387SHung-ying Tyan 	}
123*88364387SHung-ying Tyan 
124*88364387SHung-ying Tyan 	return ret;
125*88364387SHung-ying Tyan }
126*88364387SHung-ying Tyan 
127*88364387SHung-ying Tyan /**
128*88364387SHung-ying Tyan  * Send a command to the CROS-EC device and return the reply.
129*88364387SHung-ying Tyan  *
130*88364387SHung-ying Tyan  * The device's internal input/output buffers are used.
131*88364387SHung-ying Tyan  *
132*88364387SHung-ying Tyan  * @param dev		CROS-EC device
133*88364387SHung-ying Tyan  * @param cmd		Command to send (EC_CMD_...)
134*88364387SHung-ying Tyan  * @param cmd_version	Version of command to send (EC_VER_...)
135*88364387SHung-ying Tyan  * @param dout          Output data (may be NULL If dout_len=0)
136*88364387SHung-ying Tyan  * @param dout_len      Size of output data in bytes
137*88364387SHung-ying Tyan  * @param dinp          Response data (may be NULL If din_len=0).
138*88364387SHung-ying Tyan  *			If not NULL, it will be updated to point to the data
139*88364387SHung-ying Tyan  *			and will always be double word aligned (64-bits)
140*88364387SHung-ying Tyan  * @param din_len       Maximum size of response in bytes
141*88364387SHung-ying Tyan  * @return number of bytes in response, or -1 on error
142*88364387SHung-ying Tyan  */
143*88364387SHung-ying Tyan static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
144*88364387SHung-ying Tyan 		int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
145*88364387SHung-ying Tyan 		int din_len)
146*88364387SHung-ying Tyan {
147*88364387SHung-ying Tyan 	uint8_t *din;
148*88364387SHung-ying Tyan 	int len;
149*88364387SHung-ying Tyan 
150*88364387SHung-ying Tyan 	if (cmd_version != 0 && !dev->cmd_version_is_supported) {
151*88364387SHung-ying Tyan 		debug("%s: Command version >0 unsupported\n", __func__);
152*88364387SHung-ying Tyan 		return -1;
153*88364387SHung-ying Tyan 	}
154*88364387SHung-ying Tyan 	len = send_command(dev, cmd, cmd_version, dout, dout_len,
155*88364387SHung-ying Tyan 				&din, din_len);
156*88364387SHung-ying Tyan 
157*88364387SHung-ying Tyan 	/* If the command doesn't complete, wait a while */
158*88364387SHung-ying Tyan 	if (len == -EC_RES_IN_PROGRESS) {
159*88364387SHung-ying Tyan 		struct ec_response_get_comms_status *resp;
160*88364387SHung-ying Tyan 		ulong start;
161*88364387SHung-ying Tyan 
162*88364387SHung-ying Tyan 		/* Wait for command to complete */
163*88364387SHung-ying Tyan 		start = get_timer(0);
164*88364387SHung-ying Tyan 		do {
165*88364387SHung-ying Tyan 			int ret;
166*88364387SHung-ying Tyan 
167*88364387SHung-ying Tyan 			mdelay(50);	/* Insert some reasonable delay */
168*88364387SHung-ying Tyan 			ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0,
169*88364387SHung-ying Tyan 					NULL, 0,
170*88364387SHung-ying Tyan 					(uint8_t **)&resp, sizeof(*resp));
171*88364387SHung-ying Tyan 			if (ret < 0)
172*88364387SHung-ying Tyan 				return ret;
173*88364387SHung-ying Tyan 
174*88364387SHung-ying Tyan 			if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) {
175*88364387SHung-ying Tyan 				debug("%s: Command %#02x timeout\n",
176*88364387SHung-ying Tyan 				      __func__, cmd);
177*88364387SHung-ying Tyan 				return -EC_RES_TIMEOUT;
178*88364387SHung-ying Tyan 			}
179*88364387SHung-ying Tyan 		} while (resp->flags & EC_COMMS_STATUS_PROCESSING);
180*88364387SHung-ying Tyan 
181*88364387SHung-ying Tyan 		/* OK it completed, so read the status response */
182*88364387SHung-ying Tyan 		/* not sure why it was 0 for the last argument */
183*88364387SHung-ying Tyan 		len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0,
184*88364387SHung-ying Tyan 				NULL, 0, &din, din_len);
185*88364387SHung-ying Tyan 	}
186*88364387SHung-ying Tyan 
187*88364387SHung-ying Tyan 	debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, *dinp);
188*88364387SHung-ying Tyan 	if (dinp) {
189*88364387SHung-ying Tyan 		/* If we have any data to return, it must be 64bit-aligned */
190*88364387SHung-ying Tyan 		assert(len <= 0 || !((uintptr_t)din & 7));
191*88364387SHung-ying Tyan 		*dinp = din;
192*88364387SHung-ying Tyan 	}
193*88364387SHung-ying Tyan 
194*88364387SHung-ying Tyan 	return len;
195*88364387SHung-ying Tyan }
196*88364387SHung-ying Tyan 
197*88364387SHung-ying Tyan /**
198*88364387SHung-ying Tyan  * Send a command to the CROS-EC device and return the reply.
199*88364387SHung-ying Tyan  *
200*88364387SHung-ying Tyan  * The device's internal input/output buffers are used.
201*88364387SHung-ying Tyan  *
202*88364387SHung-ying Tyan  * @param dev		CROS-EC device
203*88364387SHung-ying Tyan  * @param cmd		Command to send (EC_CMD_...)
204*88364387SHung-ying Tyan  * @param cmd_version	Version of command to send (EC_VER_...)
205*88364387SHung-ying Tyan  * @param dout          Output data (may be NULL If dout_len=0)
206*88364387SHung-ying Tyan  * @param dout_len      Size of output data in bytes
207*88364387SHung-ying Tyan  * @param din           Response data (may be NULL If din_len=0).
208*88364387SHung-ying Tyan  *			It not NULL, it is a place for ec_command() to copy the
209*88364387SHung-ying Tyan  *      data to.
210*88364387SHung-ying Tyan  * @param din_len       Maximum size of response in bytes
211*88364387SHung-ying Tyan  * @return number of bytes in response, or -1 on error
212*88364387SHung-ying Tyan  */
213*88364387SHung-ying Tyan static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
214*88364387SHung-ying Tyan 		      const void *dout, int dout_len,
215*88364387SHung-ying Tyan 		      void *din, int din_len)
216*88364387SHung-ying Tyan {
217*88364387SHung-ying Tyan 	uint8_t *in_buffer;
218*88364387SHung-ying Tyan 	int len;
219*88364387SHung-ying Tyan 
220*88364387SHung-ying Tyan 	assert((din_len == 0) || din);
221*88364387SHung-ying Tyan 	len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len,
222*88364387SHung-ying Tyan 			&in_buffer, din_len);
223*88364387SHung-ying Tyan 	if (len > 0) {
224*88364387SHung-ying Tyan 		/*
225*88364387SHung-ying Tyan 		 * If we were asked to put it somewhere, do so, otherwise just
226*88364387SHung-ying Tyan 		 * disregard the result.
227*88364387SHung-ying Tyan 		 */
228*88364387SHung-ying Tyan 		if (din && in_buffer) {
229*88364387SHung-ying Tyan 			assert(len <= din_len);
230*88364387SHung-ying Tyan 			memmove(din, in_buffer, len);
231*88364387SHung-ying Tyan 		}
232*88364387SHung-ying Tyan 	}
233*88364387SHung-ying Tyan 	return len;
234*88364387SHung-ying Tyan }
235*88364387SHung-ying Tyan 
236*88364387SHung-ying Tyan int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan)
237*88364387SHung-ying Tyan {
238*88364387SHung-ying Tyan 	if (ec_command(dev, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan,
239*88364387SHung-ying Tyan 		       sizeof(scan->data)) < sizeof(scan->data))
240*88364387SHung-ying Tyan 		return -1;
241*88364387SHung-ying Tyan 
242*88364387SHung-ying Tyan 	return 0;
243*88364387SHung-ying Tyan }
244*88364387SHung-ying Tyan 
245*88364387SHung-ying Tyan int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen)
246*88364387SHung-ying Tyan {
247*88364387SHung-ying Tyan 	struct ec_response_get_version *r;
248*88364387SHung-ying Tyan 
249*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
250*88364387SHung-ying Tyan 			(uint8_t **)&r, sizeof(*r)) < sizeof(*r))
251*88364387SHung-ying Tyan 		return -1;
252*88364387SHung-ying Tyan 
253*88364387SHung-ying Tyan 	if (maxlen > sizeof(r->version_string_ro))
254*88364387SHung-ying Tyan 		maxlen = sizeof(r->version_string_ro);
255*88364387SHung-ying Tyan 
256*88364387SHung-ying Tyan 	switch (r->current_image) {
257*88364387SHung-ying Tyan 	case EC_IMAGE_RO:
258*88364387SHung-ying Tyan 		memcpy(id, r->version_string_ro, maxlen);
259*88364387SHung-ying Tyan 		break;
260*88364387SHung-ying Tyan 	case EC_IMAGE_RW:
261*88364387SHung-ying Tyan 		memcpy(id, r->version_string_rw, maxlen);
262*88364387SHung-ying Tyan 		break;
263*88364387SHung-ying Tyan 	default:
264*88364387SHung-ying Tyan 		return -1;
265*88364387SHung-ying Tyan 	}
266*88364387SHung-ying Tyan 
267*88364387SHung-ying Tyan 	id[maxlen - 1] = '\0';
268*88364387SHung-ying Tyan 	return 0;
269*88364387SHung-ying Tyan }
270*88364387SHung-ying Tyan 
271*88364387SHung-ying Tyan int cros_ec_read_version(struct cros_ec_dev *dev,
272*88364387SHung-ying Tyan 		       struct ec_response_get_version **versionp)
273*88364387SHung-ying Tyan {
274*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
275*88364387SHung-ying Tyan 			(uint8_t **)versionp, sizeof(**versionp))
276*88364387SHung-ying Tyan 			< sizeof(**versionp))
277*88364387SHung-ying Tyan 		return -1;
278*88364387SHung-ying Tyan 
279*88364387SHung-ying Tyan 	return 0;
280*88364387SHung-ying Tyan }
281*88364387SHung-ying Tyan 
282*88364387SHung-ying Tyan int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp)
283*88364387SHung-ying Tyan {
284*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0,
285*88364387SHung-ying Tyan 			(uint8_t **)strp, EC_HOST_PARAM_SIZE) < 0)
286*88364387SHung-ying Tyan 		return -1;
287*88364387SHung-ying Tyan 
288*88364387SHung-ying Tyan 	return 0;
289*88364387SHung-ying Tyan }
290*88364387SHung-ying Tyan 
291*88364387SHung-ying Tyan int cros_ec_read_current_image(struct cros_ec_dev *dev,
292*88364387SHung-ying Tyan 		enum ec_current_image *image)
293*88364387SHung-ying Tyan {
294*88364387SHung-ying Tyan 	struct ec_response_get_version *r;
295*88364387SHung-ying Tyan 
296*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0,
297*88364387SHung-ying Tyan 			(uint8_t **)&r, sizeof(*r)) < sizeof(*r))
298*88364387SHung-ying Tyan 		return -1;
299*88364387SHung-ying Tyan 
300*88364387SHung-ying Tyan 	*image = r->current_image;
301*88364387SHung-ying Tyan 	return 0;
302*88364387SHung-ying Tyan }
303*88364387SHung-ying Tyan 
304*88364387SHung-ying Tyan static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev,
305*88364387SHung-ying Tyan 				  struct ec_response_vboot_hash *hash)
306*88364387SHung-ying Tyan {
307*88364387SHung-ying Tyan 	struct ec_params_vboot_hash p;
308*88364387SHung-ying Tyan 	ulong start;
309*88364387SHung-ying Tyan 
310*88364387SHung-ying Tyan 	start = get_timer(0);
311*88364387SHung-ying Tyan 	while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
312*88364387SHung-ying Tyan 		mdelay(50);	/* Insert some reasonable delay */
313*88364387SHung-ying Tyan 
314*88364387SHung-ying Tyan 		p.cmd = EC_VBOOT_HASH_GET;
315*88364387SHung-ying Tyan 		if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
316*88364387SHung-ying Tyan 		       hash, sizeof(*hash)) < 0)
317*88364387SHung-ying Tyan 			return -1;
318*88364387SHung-ying Tyan 
319*88364387SHung-ying Tyan 		if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) {
320*88364387SHung-ying Tyan 			debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__);
321*88364387SHung-ying Tyan 			return -EC_RES_TIMEOUT;
322*88364387SHung-ying Tyan 		}
323*88364387SHung-ying Tyan 	}
324*88364387SHung-ying Tyan 	return 0;
325*88364387SHung-ying Tyan }
326*88364387SHung-ying Tyan 
327*88364387SHung-ying Tyan 
328*88364387SHung-ying Tyan int cros_ec_read_hash(struct cros_ec_dev *dev,
329*88364387SHung-ying Tyan 		struct ec_response_vboot_hash *hash)
330*88364387SHung-ying Tyan {
331*88364387SHung-ying Tyan 	struct ec_params_vboot_hash p;
332*88364387SHung-ying Tyan 	int rv;
333*88364387SHung-ying Tyan 
334*88364387SHung-ying Tyan 	p.cmd = EC_VBOOT_HASH_GET;
335*88364387SHung-ying Tyan 	if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
336*88364387SHung-ying Tyan 		       hash, sizeof(*hash)) < 0)
337*88364387SHung-ying Tyan 		return -1;
338*88364387SHung-ying Tyan 
339*88364387SHung-ying Tyan 	/* If the EC is busy calculating the hash, fidget until it's done. */
340*88364387SHung-ying Tyan 	rv = cros_ec_wait_on_hash_done(dev, hash);
341*88364387SHung-ying Tyan 	if (rv)
342*88364387SHung-ying Tyan 		return rv;
343*88364387SHung-ying Tyan 
344*88364387SHung-ying Tyan 	/* If the hash is valid, we're done. Otherwise, we have to kick it off
345*88364387SHung-ying Tyan 	 * again and wait for it to complete. Note that we explicitly assume
346*88364387SHung-ying Tyan 	 * that hashing zero bytes is always wrong, even though that would
347*88364387SHung-ying Tyan 	 * produce a valid hash value. */
348*88364387SHung-ying Tyan 	if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size)
349*88364387SHung-ying Tyan 		return 0;
350*88364387SHung-ying Tyan 
351*88364387SHung-ying Tyan 	debug("%s: No valid hash (status=%d size=%d). Compute one...\n",
352*88364387SHung-ying Tyan 	      __func__, hash->status, hash->size);
353*88364387SHung-ying Tyan 
354*88364387SHung-ying Tyan 	p.cmd = EC_VBOOT_HASH_RECALC;
355*88364387SHung-ying Tyan 	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
356*88364387SHung-ying Tyan 	p.nonce_size = 0;
357*88364387SHung-ying Tyan 	p.offset = EC_VBOOT_HASH_OFFSET_RW;
358*88364387SHung-ying Tyan 
359*88364387SHung-ying Tyan 	if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
360*88364387SHung-ying Tyan 		       hash, sizeof(*hash)) < 0)
361*88364387SHung-ying Tyan 		return -1;
362*88364387SHung-ying Tyan 
363*88364387SHung-ying Tyan 	rv = cros_ec_wait_on_hash_done(dev, hash);
364*88364387SHung-ying Tyan 	if (rv)
365*88364387SHung-ying Tyan 		return rv;
366*88364387SHung-ying Tyan 
367*88364387SHung-ying Tyan 	debug("%s: hash done\n", __func__);
368*88364387SHung-ying Tyan 
369*88364387SHung-ying Tyan 	return 0;
370*88364387SHung-ying Tyan }
371*88364387SHung-ying Tyan 
372*88364387SHung-ying Tyan static int cros_ec_invalidate_hash(struct cros_ec_dev *dev)
373*88364387SHung-ying Tyan {
374*88364387SHung-ying Tyan 	struct ec_params_vboot_hash p;
375*88364387SHung-ying Tyan 	struct ec_response_vboot_hash *hash;
376*88364387SHung-ying Tyan 
377*88364387SHung-ying Tyan 	/* We don't have an explict command for the EC to discard its current
378*88364387SHung-ying Tyan 	 * hash value, so we'll just tell it to calculate one that we know is
379*88364387SHung-ying Tyan 	 * wrong (we claim that hashing zero bytes is always invalid).
380*88364387SHung-ying Tyan 	 */
381*88364387SHung-ying Tyan 	p.cmd = EC_VBOOT_HASH_RECALC;
382*88364387SHung-ying Tyan 	p.hash_type = EC_VBOOT_HASH_TYPE_SHA256;
383*88364387SHung-ying Tyan 	p.nonce_size = 0;
384*88364387SHung-ying Tyan 	p.offset = 0;
385*88364387SHung-ying Tyan 	p.size = 0;
386*88364387SHung-ying Tyan 
387*88364387SHung-ying Tyan 	debug("%s:\n", __func__);
388*88364387SHung-ying Tyan 
389*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p),
390*88364387SHung-ying Tyan 		       (uint8_t **)&hash, sizeof(*hash)) < 0)
391*88364387SHung-ying Tyan 		return -1;
392*88364387SHung-ying Tyan 
393*88364387SHung-ying Tyan 	/* No need to wait for it to finish */
394*88364387SHung-ying Tyan 	return 0;
395*88364387SHung-ying Tyan }
396*88364387SHung-ying Tyan 
397*88364387SHung-ying Tyan int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
398*88364387SHung-ying Tyan 		uint8_t flags)
399*88364387SHung-ying Tyan {
400*88364387SHung-ying Tyan 	struct ec_params_reboot_ec p;
401*88364387SHung-ying Tyan 
402*88364387SHung-ying Tyan 	p.cmd = cmd;
403*88364387SHung-ying Tyan 	p.flags = flags;
404*88364387SHung-ying Tyan 
405*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0)
406*88364387SHung-ying Tyan 			< 0)
407*88364387SHung-ying Tyan 		return -1;
408*88364387SHung-ying Tyan 
409*88364387SHung-ying Tyan 	if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
410*88364387SHung-ying Tyan 		/*
411*88364387SHung-ying Tyan 		 * EC reboot will take place immediately so delay to allow it
412*88364387SHung-ying Tyan 		 * to complete.  Note that some reboot types (EC_REBOOT_COLD)
413*88364387SHung-ying Tyan 		 * will reboot the AP as well, in which case we won't actually
414*88364387SHung-ying Tyan 		 * get to this point.
415*88364387SHung-ying Tyan 		 */
416*88364387SHung-ying Tyan 		/*
417*88364387SHung-ying Tyan 		 * TODO(rspangler@chromium.org): Would be nice if we had a
418*88364387SHung-ying Tyan 		 * better way to determine when the reboot is complete.  Could
419*88364387SHung-ying Tyan 		 * we poll a memory-mapped LPC value?
420*88364387SHung-ying Tyan 		 */
421*88364387SHung-ying Tyan 		udelay(50000);
422*88364387SHung-ying Tyan 	}
423*88364387SHung-ying Tyan 
424*88364387SHung-ying Tyan 	return 0;
425*88364387SHung-ying Tyan }
426*88364387SHung-ying Tyan 
427*88364387SHung-ying Tyan int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
428*88364387SHung-ying Tyan {
429*88364387SHung-ying Tyan 	/* no interrupt support : always poll */
430*88364387SHung-ying Tyan 	if (!fdt_gpio_isvalid(&dev->ec_int))
431*88364387SHung-ying Tyan 		return 1;
432*88364387SHung-ying Tyan 
433*88364387SHung-ying Tyan 	return !gpio_get_value(dev->ec_int.gpio);
434*88364387SHung-ying Tyan }
435*88364387SHung-ying Tyan 
436*88364387SHung-ying Tyan int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_cros_ec_info *info)
437*88364387SHung-ying Tyan {
438*88364387SHung-ying Tyan 	if (ec_command(dev, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info,
439*88364387SHung-ying Tyan 			sizeof(*info)) < sizeof(*info))
440*88364387SHung-ying Tyan 		return -1;
441*88364387SHung-ying Tyan 
442*88364387SHung-ying Tyan 	return 0;
443*88364387SHung-ying Tyan }
444*88364387SHung-ying Tyan 
445*88364387SHung-ying Tyan int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr)
446*88364387SHung-ying Tyan {
447*88364387SHung-ying Tyan 	struct ec_response_host_event_mask *resp;
448*88364387SHung-ying Tyan 
449*88364387SHung-ying Tyan 	/*
450*88364387SHung-ying Tyan 	 * Use the B copy of the event flags, because the main copy is already
451*88364387SHung-ying Tyan 	 * used by ACPI/SMI.
452*88364387SHung-ying Tyan 	 */
453*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0,
454*88364387SHung-ying Tyan 		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp))
455*88364387SHung-ying Tyan 		return -1;
456*88364387SHung-ying Tyan 
457*88364387SHung-ying Tyan 	if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID))
458*88364387SHung-ying Tyan 		return -1;
459*88364387SHung-ying Tyan 
460*88364387SHung-ying Tyan 	*events_ptr = resp->mask;
461*88364387SHung-ying Tyan 	return 0;
462*88364387SHung-ying Tyan }
463*88364387SHung-ying Tyan 
464*88364387SHung-ying Tyan int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events)
465*88364387SHung-ying Tyan {
466*88364387SHung-ying Tyan 	struct ec_params_host_event_mask params;
467*88364387SHung-ying Tyan 
468*88364387SHung-ying Tyan 	params.mask = events;
469*88364387SHung-ying Tyan 
470*88364387SHung-ying Tyan 	/*
471*88364387SHung-ying Tyan 	 * Use the B copy of the event flags, so it affects the data returned
472*88364387SHung-ying Tyan 	 * by cros_ec_get_host_events().
473*88364387SHung-ying Tyan 	 */
474*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0,
475*88364387SHung-ying Tyan 		       &params, sizeof(params), NULL, 0) < 0)
476*88364387SHung-ying Tyan 		return -1;
477*88364387SHung-ying Tyan 
478*88364387SHung-ying Tyan 	return 0;
479*88364387SHung-ying Tyan }
480*88364387SHung-ying Tyan 
481*88364387SHung-ying Tyan int cros_ec_flash_protect(struct cros_ec_dev *dev,
482*88364387SHung-ying Tyan 		       uint32_t set_mask, uint32_t set_flags,
483*88364387SHung-ying Tyan 		       struct ec_response_flash_protect *resp)
484*88364387SHung-ying Tyan {
485*88364387SHung-ying Tyan 	struct ec_params_flash_protect params;
486*88364387SHung-ying Tyan 
487*88364387SHung-ying Tyan 	params.mask = set_mask;
488*88364387SHung-ying Tyan 	params.flags = set_flags;
489*88364387SHung-ying Tyan 
490*88364387SHung-ying Tyan 	if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
491*88364387SHung-ying Tyan 		       &params, sizeof(params),
492*88364387SHung-ying Tyan 		       resp, sizeof(*resp)) < sizeof(*resp))
493*88364387SHung-ying Tyan 		return -1;
494*88364387SHung-ying Tyan 
495*88364387SHung-ying Tyan 	return 0;
496*88364387SHung-ying Tyan }
497*88364387SHung-ying Tyan 
498*88364387SHung-ying Tyan static int cros_ec_check_version(struct cros_ec_dev *dev)
499*88364387SHung-ying Tyan {
500*88364387SHung-ying Tyan 	struct ec_params_hello req;
501*88364387SHung-ying Tyan 	struct ec_response_hello *resp;
502*88364387SHung-ying Tyan 
503*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC
504*88364387SHung-ying Tyan 	/* LPC has its own way of doing this */
505*88364387SHung-ying Tyan 	if (dev->interface == CROS_EC_IF_LPC)
506*88364387SHung-ying Tyan 		return cros_ec_lpc_check_version(dev);
507*88364387SHung-ying Tyan #endif
508*88364387SHung-ying Tyan 
509*88364387SHung-ying Tyan 	/*
510*88364387SHung-ying Tyan 	 * TODO(sjg@chromium.org).
511*88364387SHung-ying Tyan 	 * There is a strange oddity here with the EC. We could just ignore
512*88364387SHung-ying Tyan 	 * the response, i.e. pass the last two parameters as NULL and 0.
513*88364387SHung-ying Tyan 	 * In this case we won't read back very many bytes from the EC.
514*88364387SHung-ying Tyan 	 * On the I2C bus the EC gets upset about this and will try to send
515*88364387SHung-ying Tyan 	 * the bytes anyway. This means that we will have to wait for that
516*88364387SHung-ying Tyan 	 * to complete before continuing with a new EC command.
517*88364387SHung-ying Tyan 	 *
518*88364387SHung-ying Tyan 	 * This problem is probably unique to the I2C bus.
519*88364387SHung-ying Tyan 	 *
520*88364387SHung-ying Tyan 	 * So for now, just read all the data anyway.
521*88364387SHung-ying Tyan 	 */
522*88364387SHung-ying Tyan 	dev->cmd_version_is_supported = 1;
523*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
524*88364387SHung-ying Tyan 		       (uint8_t **)&resp, sizeof(*resp)) > 0) {
525*88364387SHung-ying Tyan 		/* It appears to understand new version commands */
526*88364387SHung-ying Tyan 		dev->cmd_version_is_supported = 1;
527*88364387SHung-ying Tyan 	} else {
528*88364387SHung-ying Tyan 		dev->cmd_version_is_supported = 0;
529*88364387SHung-ying Tyan 		if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req,
530*88364387SHung-ying Tyan 			      sizeof(req), (uint8_t **)&resp,
531*88364387SHung-ying Tyan 			      sizeof(*resp)) < 0) {
532*88364387SHung-ying Tyan 			debug("%s: Failed both old and new command style\n",
533*88364387SHung-ying Tyan 				__func__);
534*88364387SHung-ying Tyan 			return -1;
535*88364387SHung-ying Tyan 		}
536*88364387SHung-ying Tyan 	}
537*88364387SHung-ying Tyan 
538*88364387SHung-ying Tyan 	return 0;
539*88364387SHung-ying Tyan }
540*88364387SHung-ying Tyan 
541*88364387SHung-ying Tyan int cros_ec_test(struct cros_ec_dev *dev)
542*88364387SHung-ying Tyan {
543*88364387SHung-ying Tyan 	struct ec_params_hello req;
544*88364387SHung-ying Tyan 	struct ec_response_hello *resp;
545*88364387SHung-ying Tyan 
546*88364387SHung-ying Tyan 	req.in_data = 0x12345678;
547*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
548*88364387SHung-ying Tyan 		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
549*88364387SHung-ying Tyan 		printf("ec_command_inptr() returned error\n");
550*88364387SHung-ying Tyan 		return -1;
551*88364387SHung-ying Tyan 	}
552*88364387SHung-ying Tyan 	if (resp->out_data != req.in_data + 0x01020304) {
553*88364387SHung-ying Tyan 		printf("Received invalid handshake %x\n", resp->out_data);
554*88364387SHung-ying Tyan 		return -1;
555*88364387SHung-ying Tyan 	}
556*88364387SHung-ying Tyan 
557*88364387SHung-ying Tyan 	return 0;
558*88364387SHung-ying Tyan }
559*88364387SHung-ying Tyan 
560*88364387SHung-ying Tyan int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region,
561*88364387SHung-ying Tyan 		      uint32_t *offset, uint32_t *size)
562*88364387SHung-ying Tyan {
563*88364387SHung-ying Tyan 	struct ec_params_flash_region_info p;
564*88364387SHung-ying Tyan 	struct ec_response_flash_region_info *r;
565*88364387SHung-ying Tyan 	int ret;
566*88364387SHung-ying Tyan 
567*88364387SHung-ying Tyan 	p.region = region;
568*88364387SHung-ying Tyan 	ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO,
569*88364387SHung-ying Tyan 			 EC_VER_FLASH_REGION_INFO,
570*88364387SHung-ying Tyan 			 &p, sizeof(p), (uint8_t **)&r, sizeof(*r));
571*88364387SHung-ying Tyan 	if (ret != sizeof(*r))
572*88364387SHung-ying Tyan 		return -1;
573*88364387SHung-ying Tyan 
574*88364387SHung-ying Tyan 	if (offset)
575*88364387SHung-ying Tyan 		*offset = r->offset;
576*88364387SHung-ying Tyan 	if (size)
577*88364387SHung-ying Tyan 		*size = r->size;
578*88364387SHung-ying Tyan 
579*88364387SHung-ying Tyan 	return 0;
580*88364387SHung-ying Tyan }
581*88364387SHung-ying Tyan 
582*88364387SHung-ying Tyan int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size)
583*88364387SHung-ying Tyan {
584*88364387SHung-ying Tyan 	struct ec_params_flash_erase p;
585*88364387SHung-ying Tyan 
586*88364387SHung-ying Tyan 	p.offset = offset;
587*88364387SHung-ying Tyan 	p.size = size;
588*88364387SHung-ying Tyan 	return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p),
589*88364387SHung-ying Tyan 			NULL, 0);
590*88364387SHung-ying Tyan }
591*88364387SHung-ying Tyan 
592*88364387SHung-ying Tyan /**
593*88364387SHung-ying Tyan  * Write a single block to the flash
594*88364387SHung-ying Tyan  *
595*88364387SHung-ying Tyan  * Write a block of data to the EC flash. The size must not exceed the flash
596*88364387SHung-ying Tyan  * write block size which you can obtain from cros_ec_flash_write_burst_size().
597*88364387SHung-ying Tyan  *
598*88364387SHung-ying Tyan  * The offset starts at 0. You can obtain the region information from
599*88364387SHung-ying Tyan  * cros_ec_flash_offset() to find out where to write for a particular region.
600*88364387SHung-ying Tyan  *
601*88364387SHung-ying Tyan  * Attempting to write to the region where the EC is currently running from
602*88364387SHung-ying Tyan  * will result in an error.
603*88364387SHung-ying Tyan  *
604*88364387SHung-ying Tyan  * @param dev		CROS-EC device
605*88364387SHung-ying Tyan  * @param data		Pointer to data buffer to write
606*88364387SHung-ying Tyan  * @param offset	Offset within flash to write to.
607*88364387SHung-ying Tyan  * @param size		Number of bytes to write
608*88364387SHung-ying Tyan  * @return 0 if ok, -1 on error
609*88364387SHung-ying Tyan  */
610*88364387SHung-ying Tyan static int cros_ec_flash_write_block(struct cros_ec_dev *dev,
611*88364387SHung-ying Tyan 		const uint8_t *data, uint32_t offset, uint32_t size)
612*88364387SHung-ying Tyan {
613*88364387SHung-ying Tyan 	struct ec_params_flash_write p;
614*88364387SHung-ying Tyan 
615*88364387SHung-ying Tyan 	p.offset = offset;
616*88364387SHung-ying Tyan 	p.size = size;
617*88364387SHung-ying Tyan 	assert(data && p.size <= sizeof(p.data));
618*88364387SHung-ying Tyan 	memcpy(p.data, data, p.size);
619*88364387SHung-ying Tyan 
620*88364387SHung-ying Tyan 	return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0,
621*88364387SHung-ying Tyan 			  &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1;
622*88364387SHung-ying Tyan }
623*88364387SHung-ying Tyan 
624*88364387SHung-ying Tyan /**
625*88364387SHung-ying Tyan  * Return optimal flash write burst size
626*88364387SHung-ying Tyan  */
627*88364387SHung-ying Tyan static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev)
628*88364387SHung-ying Tyan {
629*88364387SHung-ying Tyan 	struct ec_params_flash_write p;
630*88364387SHung-ying Tyan 	return sizeof(p.data);
631*88364387SHung-ying Tyan }
632*88364387SHung-ying Tyan 
633*88364387SHung-ying Tyan /**
634*88364387SHung-ying Tyan  * Check if a block of data is erased (all 0xff)
635*88364387SHung-ying Tyan  *
636*88364387SHung-ying Tyan  * This function is useful when dealing with flash, for checking whether a
637*88364387SHung-ying Tyan  * data block is erased and thus does not need to be programmed.
638*88364387SHung-ying Tyan  *
639*88364387SHung-ying Tyan  * @param data		Pointer to data to check (must be word-aligned)
640*88364387SHung-ying Tyan  * @param size		Number of bytes to check (must be word-aligned)
641*88364387SHung-ying Tyan  * @return 0 if erased, non-zero if any word is not erased
642*88364387SHung-ying Tyan  */
643*88364387SHung-ying Tyan static int cros_ec_data_is_erased(const uint32_t *data, int size)
644*88364387SHung-ying Tyan {
645*88364387SHung-ying Tyan 	assert(!(size & 3));
646*88364387SHung-ying Tyan 	size /= sizeof(uint32_t);
647*88364387SHung-ying Tyan 	for (; size > 0; size -= 4, data++)
648*88364387SHung-ying Tyan 		if (*data != -1U)
649*88364387SHung-ying Tyan 			return 0;
650*88364387SHung-ying Tyan 
651*88364387SHung-ying Tyan 	return 1;
652*88364387SHung-ying Tyan }
653*88364387SHung-ying Tyan 
654*88364387SHung-ying Tyan int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data,
655*88364387SHung-ying Tyan 		     uint32_t offset, uint32_t size)
656*88364387SHung-ying Tyan {
657*88364387SHung-ying Tyan 	uint32_t burst = cros_ec_flash_write_burst_size(dev);
658*88364387SHung-ying Tyan 	uint32_t end, off;
659*88364387SHung-ying Tyan 	int ret;
660*88364387SHung-ying Tyan 
661*88364387SHung-ying Tyan 	/*
662*88364387SHung-ying Tyan 	 * TODO: round up to the nearest multiple of write size.  Can get away
663*88364387SHung-ying Tyan 	 * without that on link right now because its write size is 4 bytes.
664*88364387SHung-ying Tyan 	 */
665*88364387SHung-ying Tyan 	end = offset + size;
666*88364387SHung-ying Tyan 	for (off = offset; off < end; off += burst, data += burst) {
667*88364387SHung-ying Tyan 		uint32_t todo;
668*88364387SHung-ying Tyan 
669*88364387SHung-ying Tyan 		/* If the data is empty, there is no point in programming it */
670*88364387SHung-ying Tyan 		todo = min(end - off, burst);
671*88364387SHung-ying Tyan 		if (dev->optimise_flash_write &&
672*88364387SHung-ying Tyan 				cros_ec_data_is_erased((uint32_t *)data, todo))
673*88364387SHung-ying Tyan 			continue;
674*88364387SHung-ying Tyan 
675*88364387SHung-ying Tyan 		ret = cros_ec_flash_write_block(dev, data, off, todo);
676*88364387SHung-ying Tyan 		if (ret)
677*88364387SHung-ying Tyan 			return ret;
678*88364387SHung-ying Tyan 	}
679*88364387SHung-ying Tyan 
680*88364387SHung-ying Tyan 	return 0;
681*88364387SHung-ying Tyan }
682*88364387SHung-ying Tyan 
683*88364387SHung-ying Tyan /**
684*88364387SHung-ying Tyan  * Read a single block from the flash
685*88364387SHung-ying Tyan  *
686*88364387SHung-ying Tyan  * Read a block of data from the EC flash. The size must not exceed the flash
687*88364387SHung-ying Tyan  * write block size which you can obtain from cros_ec_flash_write_burst_size().
688*88364387SHung-ying Tyan  *
689*88364387SHung-ying Tyan  * The offset starts at 0. You can obtain the region information from
690*88364387SHung-ying Tyan  * cros_ec_flash_offset() to find out where to read for a particular region.
691*88364387SHung-ying Tyan  *
692*88364387SHung-ying Tyan  * @param dev		CROS-EC device
693*88364387SHung-ying Tyan  * @param data		Pointer to data buffer to read into
694*88364387SHung-ying Tyan  * @param offset	Offset within flash to read from
695*88364387SHung-ying Tyan  * @param size		Number of bytes to read
696*88364387SHung-ying Tyan  * @return 0 if ok, -1 on error
697*88364387SHung-ying Tyan  */
698*88364387SHung-ying Tyan static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data,
699*88364387SHung-ying Tyan 				 uint32_t offset, uint32_t size)
700*88364387SHung-ying Tyan {
701*88364387SHung-ying Tyan 	struct ec_params_flash_read p;
702*88364387SHung-ying Tyan 
703*88364387SHung-ying Tyan 	p.offset = offset;
704*88364387SHung-ying Tyan 	p.size = size;
705*88364387SHung-ying Tyan 
706*88364387SHung-ying Tyan 	return ec_command(dev, EC_CMD_FLASH_READ, 0,
707*88364387SHung-ying Tyan 			  &p, sizeof(p), data, size) >= 0 ? 0 : -1;
708*88364387SHung-ying Tyan }
709*88364387SHung-ying Tyan 
710*88364387SHung-ying Tyan int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset,
711*88364387SHung-ying Tyan 		    uint32_t size)
712*88364387SHung-ying Tyan {
713*88364387SHung-ying Tyan 	uint32_t burst = cros_ec_flash_write_burst_size(dev);
714*88364387SHung-ying Tyan 	uint32_t end, off;
715*88364387SHung-ying Tyan 	int ret;
716*88364387SHung-ying Tyan 
717*88364387SHung-ying Tyan 	end = offset + size;
718*88364387SHung-ying Tyan 	for (off = offset; off < end; off += burst, data += burst) {
719*88364387SHung-ying Tyan 		ret = cros_ec_flash_read_block(dev, data, off,
720*88364387SHung-ying Tyan 					    min(end - off, burst));
721*88364387SHung-ying Tyan 		if (ret)
722*88364387SHung-ying Tyan 			return ret;
723*88364387SHung-ying Tyan 	}
724*88364387SHung-ying Tyan 
725*88364387SHung-ying Tyan 	return 0;
726*88364387SHung-ying Tyan }
727*88364387SHung-ying Tyan 
728*88364387SHung-ying Tyan int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
729*88364387SHung-ying Tyan 			 const uint8_t *image, int image_size)
730*88364387SHung-ying Tyan {
731*88364387SHung-ying Tyan 	uint32_t rw_offset, rw_size;
732*88364387SHung-ying Tyan 	int ret;
733*88364387SHung-ying Tyan 
734*88364387SHung-ying Tyan 	if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size))
735*88364387SHung-ying Tyan 		return -1;
736*88364387SHung-ying Tyan 	if (image_size > rw_size)
737*88364387SHung-ying Tyan 		return -1;
738*88364387SHung-ying Tyan 
739*88364387SHung-ying Tyan 	/* Invalidate the existing hash, just in case the AP reboots
740*88364387SHung-ying Tyan 	 * unexpectedly during the update. If that happened, the EC RW firmware
741*88364387SHung-ying Tyan 	 * would be invalid, but the EC would still have the original hash.
742*88364387SHung-ying Tyan 	 */
743*88364387SHung-ying Tyan 	ret = cros_ec_invalidate_hash(dev);
744*88364387SHung-ying Tyan 	if (ret)
745*88364387SHung-ying Tyan 		return ret;
746*88364387SHung-ying Tyan 
747*88364387SHung-ying Tyan 	/*
748*88364387SHung-ying Tyan 	 * Erase the entire RW section, so that the EC doesn't see any garbage
749*88364387SHung-ying Tyan 	 * past the new image if it's smaller than the current image.
750*88364387SHung-ying Tyan 	 *
751*88364387SHung-ying Tyan 	 * TODO: could optimize this to erase just the current image, since
752*88364387SHung-ying Tyan 	 * presumably everything past that is 0xff's.  But would still need to
753*88364387SHung-ying Tyan 	 * round up to the nearest multiple of erase size.
754*88364387SHung-ying Tyan 	 */
755*88364387SHung-ying Tyan 	ret = cros_ec_flash_erase(dev, rw_offset, rw_size);
756*88364387SHung-ying Tyan 	if (ret)
757*88364387SHung-ying Tyan 		return ret;
758*88364387SHung-ying Tyan 
759*88364387SHung-ying Tyan 	/* Write the image */
760*88364387SHung-ying Tyan 	ret = cros_ec_flash_write(dev, image, rw_offset, image_size);
761*88364387SHung-ying Tyan 	if (ret)
762*88364387SHung-ying Tyan 		return ret;
763*88364387SHung-ying Tyan 
764*88364387SHung-ying Tyan 	return 0;
765*88364387SHung-ying Tyan }
766*88364387SHung-ying Tyan 
767*88364387SHung-ying Tyan int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block)
768*88364387SHung-ying Tyan {
769*88364387SHung-ying Tyan 	struct ec_params_vbnvcontext p;
770*88364387SHung-ying Tyan 	int len;
771*88364387SHung-ying Tyan 
772*88364387SHung-ying Tyan 	p.op = EC_VBNV_CONTEXT_OP_READ;
773*88364387SHung-ying Tyan 
774*88364387SHung-ying Tyan 	len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
775*88364387SHung-ying Tyan 			&p, sizeof(p), block, EC_VBNV_BLOCK_SIZE);
776*88364387SHung-ying Tyan 	if (len < EC_VBNV_BLOCK_SIZE)
777*88364387SHung-ying Tyan 		return -1;
778*88364387SHung-ying Tyan 
779*88364387SHung-ying Tyan 	return 0;
780*88364387SHung-ying Tyan }
781*88364387SHung-ying Tyan 
782*88364387SHung-ying Tyan int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
783*88364387SHung-ying Tyan {
784*88364387SHung-ying Tyan 	struct ec_params_vbnvcontext p;
785*88364387SHung-ying Tyan 	int len;
786*88364387SHung-ying Tyan 
787*88364387SHung-ying Tyan 	p.op = EC_VBNV_CONTEXT_OP_WRITE;
788*88364387SHung-ying Tyan 	memcpy(p.block, block, sizeof(p.block));
789*88364387SHung-ying Tyan 
790*88364387SHung-ying Tyan 	len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT,
791*88364387SHung-ying Tyan 			&p, sizeof(p), NULL, 0);
792*88364387SHung-ying Tyan 	if (len < 0)
793*88364387SHung-ying Tyan 		return -1;
794*88364387SHung-ying Tyan 
795*88364387SHung-ying Tyan 	return 0;
796*88364387SHung-ying Tyan }
797*88364387SHung-ying Tyan 
798*88364387SHung-ying Tyan int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state)
799*88364387SHung-ying Tyan {
800*88364387SHung-ying Tyan 	struct ec_params_ldo_set params;
801*88364387SHung-ying Tyan 
802*88364387SHung-ying Tyan 	params.index = index;
803*88364387SHung-ying Tyan 	params.state = state;
804*88364387SHung-ying Tyan 
805*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0,
806*88364387SHung-ying Tyan 		       &params, sizeof(params),
807*88364387SHung-ying Tyan 		       NULL, 0))
808*88364387SHung-ying Tyan 		return -1;
809*88364387SHung-ying Tyan 
810*88364387SHung-ying Tyan 	return 0;
811*88364387SHung-ying Tyan }
812*88364387SHung-ying Tyan 
813*88364387SHung-ying Tyan int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
814*88364387SHung-ying Tyan {
815*88364387SHung-ying Tyan 	struct ec_params_ldo_get params;
816*88364387SHung-ying Tyan 	struct ec_response_ldo_get *resp;
817*88364387SHung-ying Tyan 
818*88364387SHung-ying Tyan 	params.index = index;
819*88364387SHung-ying Tyan 
820*88364387SHung-ying Tyan 	if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
821*88364387SHung-ying Tyan 		       &params, sizeof(params),
822*88364387SHung-ying Tyan 		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp))
823*88364387SHung-ying Tyan 		return -1;
824*88364387SHung-ying Tyan 
825*88364387SHung-ying Tyan 	*state = resp->state;
826*88364387SHung-ying Tyan 
827*88364387SHung-ying Tyan 	return 0;
828*88364387SHung-ying Tyan }
829*88364387SHung-ying Tyan 
830*88364387SHung-ying Tyan /**
831*88364387SHung-ying Tyan  * Decode MBKP details from the device tree and allocate a suitable device.
832*88364387SHung-ying Tyan  *
833*88364387SHung-ying Tyan  * @param blob		Device tree blob
834*88364387SHung-ying Tyan  * @param node		Node to decode from
835*88364387SHung-ying Tyan  * @param devp		Returns a pointer to the new allocated device
836*88364387SHung-ying Tyan  * @return 0 if ok, -1 on error
837*88364387SHung-ying Tyan  */
838*88364387SHung-ying Tyan static int cros_ec_decode_fdt(const void *blob, int node,
839*88364387SHung-ying Tyan 		struct cros_ec_dev **devp)
840*88364387SHung-ying Tyan {
841*88364387SHung-ying Tyan 	enum fdt_compat_id compat;
842*88364387SHung-ying Tyan 	struct cros_ec_dev *dev;
843*88364387SHung-ying Tyan 	int parent;
844*88364387SHung-ying Tyan 
845*88364387SHung-ying Tyan 	/* See what type of parent we are inside (this is expensive) */
846*88364387SHung-ying Tyan 	parent = fdt_parent_offset(blob, node);
847*88364387SHung-ying Tyan 	if (parent < 0) {
848*88364387SHung-ying Tyan 		debug("%s: Cannot find node parent\n", __func__);
849*88364387SHung-ying Tyan 		return -1;
850*88364387SHung-ying Tyan 	}
851*88364387SHung-ying Tyan 
852*88364387SHung-ying Tyan 	dev = &static_dev;
853*88364387SHung-ying Tyan 	dev->node = node;
854*88364387SHung-ying Tyan 	dev->parent_node = parent;
855*88364387SHung-ying Tyan 
856*88364387SHung-ying Tyan 	compat = fdtdec_lookup(blob, parent);
857*88364387SHung-ying Tyan 	switch (compat) {
858*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_SPI
859*88364387SHung-ying Tyan 	case COMPAT_SAMSUNG_EXYNOS_SPI:
860*88364387SHung-ying Tyan 		dev->interface = CROS_EC_IF_SPI;
861*88364387SHung-ying Tyan 		if (cros_ec_spi_decode_fdt(dev, blob))
862*88364387SHung-ying Tyan 			return -1;
863*88364387SHung-ying Tyan 		break;
864*88364387SHung-ying Tyan #endif
865*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_I2C
866*88364387SHung-ying Tyan 	case COMPAT_SAMSUNG_S3C2440_I2C:
867*88364387SHung-ying Tyan 		dev->interface = CROS_EC_IF_I2C;
868*88364387SHung-ying Tyan 		if (cros_ec_i2c_decode_fdt(dev, blob))
869*88364387SHung-ying Tyan 			return -1;
870*88364387SHung-ying Tyan 		break;
871*88364387SHung-ying Tyan #endif
872*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC
873*88364387SHung-ying Tyan 	case COMPAT_INTEL_LPC:
874*88364387SHung-ying Tyan 		dev->interface = CROS_EC_IF_LPC;
875*88364387SHung-ying Tyan 		break;
876*88364387SHung-ying Tyan #endif
877*88364387SHung-ying Tyan 	default:
878*88364387SHung-ying Tyan 		debug("%s: Unknown compat id %d\n", __func__, compat);
879*88364387SHung-ying Tyan 		return -1;
880*88364387SHung-ying Tyan 	}
881*88364387SHung-ying Tyan 
882*88364387SHung-ying Tyan 	fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
883*88364387SHung-ying Tyan 	dev->optimise_flash_write = fdtdec_get_bool(blob, node,
884*88364387SHung-ying Tyan 						    "optimise-flash-write");
885*88364387SHung-ying Tyan 	*devp = dev;
886*88364387SHung-ying Tyan 
887*88364387SHung-ying Tyan 	return 0;
888*88364387SHung-ying Tyan }
889*88364387SHung-ying Tyan 
890*88364387SHung-ying Tyan int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
891*88364387SHung-ying Tyan {
892*88364387SHung-ying Tyan 	char id[MSG_BYTES];
893*88364387SHung-ying Tyan 	struct cros_ec_dev *dev;
894*88364387SHung-ying Tyan 	int node = 0;
895*88364387SHung-ying Tyan 
896*88364387SHung-ying Tyan 	*cros_ecp = NULL;
897*88364387SHung-ying Tyan 	do {
898*88364387SHung-ying Tyan 		node = fdtdec_next_compatible(blob, node,
899*88364387SHung-ying Tyan 					      COMPAT_GOOGLE_CROS_EC);
900*88364387SHung-ying Tyan 		if (node < 0) {
901*88364387SHung-ying Tyan 			debug("%s: Node not found\n", __func__);
902*88364387SHung-ying Tyan 			return 0;
903*88364387SHung-ying Tyan 		}
904*88364387SHung-ying Tyan 	} while (!fdtdec_get_is_enabled(blob, node));
905*88364387SHung-ying Tyan 
906*88364387SHung-ying Tyan 	if (cros_ec_decode_fdt(blob, node, &dev)) {
907*88364387SHung-ying Tyan 		debug("%s: Failed to decode device.\n", __func__);
908*88364387SHung-ying Tyan 		return -CROS_EC_ERR_FDT_DECODE;
909*88364387SHung-ying Tyan 	}
910*88364387SHung-ying Tyan 
911*88364387SHung-ying Tyan 	switch (dev->interface) {
912*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_SPI
913*88364387SHung-ying Tyan 	case CROS_EC_IF_SPI:
914*88364387SHung-ying Tyan 		if (cros_ec_spi_init(dev, blob)) {
915*88364387SHung-ying Tyan 			debug("%s: Could not setup SPI interface\n", __func__);
916*88364387SHung-ying Tyan 			return -CROS_EC_ERR_DEV_INIT;
917*88364387SHung-ying Tyan 		}
918*88364387SHung-ying Tyan 		break;
919*88364387SHung-ying Tyan #endif
920*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_I2C
921*88364387SHung-ying Tyan 	case CROS_EC_IF_I2C:
922*88364387SHung-ying Tyan 		if (cros_ec_i2c_init(dev, blob))
923*88364387SHung-ying Tyan 			return -CROS_EC_ERR_DEV_INIT;
924*88364387SHung-ying Tyan 		break;
925*88364387SHung-ying Tyan #endif
926*88364387SHung-ying Tyan #ifdef CONFIG_CROS_EC_LPC
927*88364387SHung-ying Tyan 	case CROS_EC_IF_LPC:
928*88364387SHung-ying Tyan 		if (cros_ec_lpc_init(dev, blob))
929*88364387SHung-ying Tyan 			return -CROS_EC_ERR_DEV_INIT;
930*88364387SHung-ying Tyan 		break;
931*88364387SHung-ying Tyan #endif
932*88364387SHung-ying Tyan 	case CROS_EC_IF_NONE:
933*88364387SHung-ying Tyan 	default:
934*88364387SHung-ying Tyan 		return 0;
935*88364387SHung-ying Tyan 	}
936*88364387SHung-ying Tyan 
937*88364387SHung-ying Tyan 	/* we will poll the EC interrupt line */
938*88364387SHung-ying Tyan 	fdtdec_setup_gpio(&dev->ec_int);
939*88364387SHung-ying Tyan 	if (fdt_gpio_isvalid(&dev->ec_int))
940*88364387SHung-ying Tyan 		gpio_direction_input(dev->ec_int.gpio);
941*88364387SHung-ying Tyan 
942*88364387SHung-ying Tyan 	if (cros_ec_check_version(dev)) {
943*88364387SHung-ying Tyan 		debug("%s: Could not detect CROS-EC version\n", __func__);
944*88364387SHung-ying Tyan 		return -CROS_EC_ERR_CHECK_VERSION;
945*88364387SHung-ying Tyan 	}
946*88364387SHung-ying Tyan 
947*88364387SHung-ying Tyan 	if (cros_ec_read_id(dev, id, sizeof(id))) {
948*88364387SHung-ying Tyan 		debug("%s: Could not read KBC ID\n", __func__);
949*88364387SHung-ying Tyan 		return -CROS_EC_ERR_READ_ID;
950*88364387SHung-ying Tyan 	}
951*88364387SHung-ying Tyan 
952*88364387SHung-ying Tyan 	/* Remember this device for use by the cros_ec command */
953*88364387SHung-ying Tyan 	last_dev = *cros_ecp = dev;
954*88364387SHung-ying Tyan 	debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
955*88364387SHung-ying Tyan 
956*88364387SHung-ying Tyan 	return 0;
957*88364387SHung-ying Tyan }
958*88364387SHung-ying Tyan 
959*88364387SHung-ying Tyan #ifdef CONFIG_CMD_CROS_EC
960*88364387SHung-ying Tyan int cros_ec_decode_region(int argc, char * const argv[])
961*88364387SHung-ying Tyan {
962*88364387SHung-ying Tyan 	if (argc > 0) {
963*88364387SHung-ying Tyan 		if (0 == strcmp(*argv, "rw"))
964*88364387SHung-ying Tyan 			return EC_FLASH_REGION_RW;
965*88364387SHung-ying Tyan 		else if (0 == strcmp(*argv, "ro"))
966*88364387SHung-ying Tyan 			return EC_FLASH_REGION_RO;
967*88364387SHung-ying Tyan 
968*88364387SHung-ying Tyan 		debug("%s: Invalid region '%s'\n", __func__, *argv);
969*88364387SHung-ying Tyan 	} else {
970*88364387SHung-ying Tyan 		debug("%s: Missing region parameter\n", __func__);
971*88364387SHung-ying Tyan 	}
972*88364387SHung-ying Tyan 
973*88364387SHung-ying Tyan 	return -1;
974*88364387SHung-ying Tyan }
975*88364387SHung-ying Tyan 
976*88364387SHung-ying Tyan /**
977*88364387SHung-ying Tyan  * Perform a flash read or write command
978*88364387SHung-ying Tyan  *
979*88364387SHung-ying Tyan  * @param dev		CROS-EC device to read/write
980*88364387SHung-ying Tyan  * @param is_write	1 do to a write, 0 to do a read
981*88364387SHung-ying Tyan  * @param argc		Number of arguments
982*88364387SHung-ying Tyan  * @param argv		Arguments (2 is region, 3 is address)
983*88364387SHung-ying Tyan  * @return 0 for ok, 1 for a usage error or -ve for ec command error
984*88364387SHung-ying Tyan  *	(negative EC_RES_...)
985*88364387SHung-ying Tyan  */
986*88364387SHung-ying Tyan static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
987*88364387SHung-ying Tyan 			 char * const argv[])
988*88364387SHung-ying Tyan {
989*88364387SHung-ying Tyan 	uint32_t offset, size = -1U, region_size;
990*88364387SHung-ying Tyan 	unsigned long addr;
991*88364387SHung-ying Tyan 	char *endp;
992*88364387SHung-ying Tyan 	int region;
993*88364387SHung-ying Tyan 	int ret;
994*88364387SHung-ying Tyan 
995*88364387SHung-ying Tyan 	region = cros_ec_decode_region(argc - 2, argv + 2);
996*88364387SHung-ying Tyan 	if (region == -1)
997*88364387SHung-ying Tyan 		return 1;
998*88364387SHung-ying Tyan 	if (argc < 4)
999*88364387SHung-ying Tyan 		return 1;
1000*88364387SHung-ying Tyan 	addr = simple_strtoul(argv[3], &endp, 16);
1001*88364387SHung-ying Tyan 	if (*argv[3] == 0 || *endp != 0)
1002*88364387SHung-ying Tyan 		return 1;
1003*88364387SHung-ying Tyan 	if (argc > 4) {
1004*88364387SHung-ying Tyan 		size = simple_strtoul(argv[4], &endp, 16);
1005*88364387SHung-ying Tyan 		if (*argv[4] == 0 || *endp != 0)
1006*88364387SHung-ying Tyan 			return 1;
1007*88364387SHung-ying Tyan 	}
1008*88364387SHung-ying Tyan 
1009*88364387SHung-ying Tyan 	ret = cros_ec_flash_offset(dev, region, &offset, &region_size);
1010*88364387SHung-ying Tyan 	if (ret) {
1011*88364387SHung-ying Tyan 		debug("%s: Could not read region info\n", __func__);
1012*88364387SHung-ying Tyan 		return ret;
1013*88364387SHung-ying Tyan 	}
1014*88364387SHung-ying Tyan 	if (size == -1U)
1015*88364387SHung-ying Tyan 		size = region_size;
1016*88364387SHung-ying Tyan 
1017*88364387SHung-ying Tyan 	ret = is_write ?
1018*88364387SHung-ying Tyan 		cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) :
1019*88364387SHung-ying Tyan 		cros_ec_flash_read(dev, (uint8_t *)addr, offset, size);
1020*88364387SHung-ying Tyan 	if (ret) {
1021*88364387SHung-ying Tyan 		debug("%s: Could not %s region\n", __func__,
1022*88364387SHung-ying Tyan 		      is_write ? "write" : "read");
1023*88364387SHung-ying Tyan 		return ret;
1024*88364387SHung-ying Tyan 	}
1025*88364387SHung-ying Tyan 
1026*88364387SHung-ying Tyan 	return 0;
1027*88364387SHung-ying Tyan }
1028*88364387SHung-ying Tyan 
1029*88364387SHung-ying Tyan static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1030*88364387SHung-ying Tyan {
1031*88364387SHung-ying Tyan 	struct cros_ec_dev *dev = last_dev;
1032*88364387SHung-ying Tyan 	const char *cmd;
1033*88364387SHung-ying Tyan 	int ret = 0;
1034*88364387SHung-ying Tyan 
1035*88364387SHung-ying Tyan 	if (argc < 2)
1036*88364387SHung-ying Tyan 		return CMD_RET_USAGE;
1037*88364387SHung-ying Tyan 
1038*88364387SHung-ying Tyan 	cmd = argv[1];
1039*88364387SHung-ying Tyan 	if (0 == strcmp("init", cmd)) {
1040*88364387SHung-ying Tyan 		ret = cros_ec_init(gd->fdt_blob, &dev);
1041*88364387SHung-ying Tyan 		if (ret) {
1042*88364387SHung-ying Tyan 			printf("Could not init cros_ec device (err %d)\n", ret);
1043*88364387SHung-ying Tyan 			return 1;
1044*88364387SHung-ying Tyan 		}
1045*88364387SHung-ying Tyan 		return 0;
1046*88364387SHung-ying Tyan 	}
1047*88364387SHung-ying Tyan 
1048*88364387SHung-ying Tyan 	/* Just use the last allocated device; there should be only one */
1049*88364387SHung-ying Tyan 	if (!last_dev) {
1050*88364387SHung-ying Tyan 		printf("No CROS-EC device available\n");
1051*88364387SHung-ying Tyan 		return 1;
1052*88364387SHung-ying Tyan 	}
1053*88364387SHung-ying Tyan 	if (0 == strcmp("id", cmd)) {
1054*88364387SHung-ying Tyan 		char id[MSG_BYTES];
1055*88364387SHung-ying Tyan 
1056*88364387SHung-ying Tyan 		if (cros_ec_read_id(dev, id, sizeof(id))) {
1057*88364387SHung-ying Tyan 			debug("%s: Could not read KBC ID\n", __func__);
1058*88364387SHung-ying Tyan 			return 1;
1059*88364387SHung-ying Tyan 		}
1060*88364387SHung-ying Tyan 		printf("%s\n", id);
1061*88364387SHung-ying Tyan 	} else if (0 == strcmp("info", cmd)) {
1062*88364387SHung-ying Tyan 		struct ec_response_cros_ec_info info;
1063*88364387SHung-ying Tyan 
1064*88364387SHung-ying Tyan 		if (cros_ec_info(dev, &info)) {
1065*88364387SHung-ying Tyan 			debug("%s: Could not read KBC info\n", __func__);
1066*88364387SHung-ying Tyan 			return 1;
1067*88364387SHung-ying Tyan 		}
1068*88364387SHung-ying Tyan 		printf("rows     = %u\n", info.rows);
1069*88364387SHung-ying Tyan 		printf("cols     = %u\n", info.cols);
1070*88364387SHung-ying Tyan 		printf("switches = %#x\n", info.switches);
1071*88364387SHung-ying Tyan 	} else if (0 == strcmp("curimage", cmd)) {
1072*88364387SHung-ying Tyan 		enum ec_current_image image;
1073*88364387SHung-ying Tyan 
1074*88364387SHung-ying Tyan 		if (cros_ec_read_current_image(dev, &image)) {
1075*88364387SHung-ying Tyan 			debug("%s: Could not read KBC image\n", __func__);
1076*88364387SHung-ying Tyan 			return 1;
1077*88364387SHung-ying Tyan 		}
1078*88364387SHung-ying Tyan 		printf("%d\n", image);
1079*88364387SHung-ying Tyan 	} else if (0 == strcmp("hash", cmd)) {
1080*88364387SHung-ying Tyan 		struct ec_response_vboot_hash hash;
1081*88364387SHung-ying Tyan 		int i;
1082*88364387SHung-ying Tyan 
1083*88364387SHung-ying Tyan 		if (cros_ec_read_hash(dev, &hash)) {
1084*88364387SHung-ying Tyan 			debug("%s: Could not read KBC hash\n", __func__);
1085*88364387SHung-ying Tyan 			return 1;
1086*88364387SHung-ying Tyan 		}
1087*88364387SHung-ying Tyan 
1088*88364387SHung-ying Tyan 		if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256)
1089*88364387SHung-ying Tyan 			printf("type:    SHA-256\n");
1090*88364387SHung-ying Tyan 		else
1091*88364387SHung-ying Tyan 			printf("type:    %d\n", hash.hash_type);
1092*88364387SHung-ying Tyan 
1093*88364387SHung-ying Tyan 		printf("offset:  0x%08x\n", hash.offset);
1094*88364387SHung-ying Tyan 		printf("size:    0x%08x\n", hash.size);
1095*88364387SHung-ying Tyan 
1096*88364387SHung-ying Tyan 		printf("digest:  ");
1097*88364387SHung-ying Tyan 		for (i = 0; i < hash.digest_size; i++)
1098*88364387SHung-ying Tyan 			printf("%02x", hash.hash_digest[i]);
1099*88364387SHung-ying Tyan 		printf("\n");
1100*88364387SHung-ying Tyan 	} else if (0 == strcmp("reboot", cmd)) {
1101*88364387SHung-ying Tyan 		int region;
1102*88364387SHung-ying Tyan 		enum ec_reboot_cmd cmd;
1103*88364387SHung-ying Tyan 
1104*88364387SHung-ying Tyan 		if (argc >= 3 && !strcmp(argv[2], "cold"))
1105*88364387SHung-ying Tyan 			cmd = EC_REBOOT_COLD;
1106*88364387SHung-ying Tyan 		else {
1107*88364387SHung-ying Tyan 			region = cros_ec_decode_region(argc - 2, argv + 2);
1108*88364387SHung-ying Tyan 			if (region == EC_FLASH_REGION_RO)
1109*88364387SHung-ying Tyan 				cmd = EC_REBOOT_JUMP_RO;
1110*88364387SHung-ying Tyan 			else if (region == EC_FLASH_REGION_RW)
1111*88364387SHung-ying Tyan 				cmd = EC_REBOOT_JUMP_RW;
1112*88364387SHung-ying Tyan 			else
1113*88364387SHung-ying Tyan 				return CMD_RET_USAGE;
1114*88364387SHung-ying Tyan 		}
1115*88364387SHung-ying Tyan 
1116*88364387SHung-ying Tyan 		if (cros_ec_reboot(dev, cmd, 0)) {
1117*88364387SHung-ying Tyan 			debug("%s: Could not reboot KBC\n", __func__);
1118*88364387SHung-ying Tyan 			return 1;
1119*88364387SHung-ying Tyan 		}
1120*88364387SHung-ying Tyan 	} else if (0 == strcmp("events", cmd)) {
1121*88364387SHung-ying Tyan 		uint32_t events;
1122*88364387SHung-ying Tyan 
1123*88364387SHung-ying Tyan 		if (cros_ec_get_host_events(dev, &events)) {
1124*88364387SHung-ying Tyan 			debug("%s: Could not read host events\n", __func__);
1125*88364387SHung-ying Tyan 			return 1;
1126*88364387SHung-ying Tyan 		}
1127*88364387SHung-ying Tyan 		printf("0x%08x\n", events);
1128*88364387SHung-ying Tyan 	} else if (0 == strcmp("clrevents", cmd)) {
1129*88364387SHung-ying Tyan 		uint32_t events = 0x7fffffff;
1130*88364387SHung-ying Tyan 
1131*88364387SHung-ying Tyan 		if (argc >= 3)
1132*88364387SHung-ying Tyan 			events = simple_strtol(argv[2], NULL, 0);
1133*88364387SHung-ying Tyan 
1134*88364387SHung-ying Tyan 		if (cros_ec_clear_host_events(dev, events)) {
1135*88364387SHung-ying Tyan 			debug("%s: Could not clear host events\n", __func__);
1136*88364387SHung-ying Tyan 			return 1;
1137*88364387SHung-ying Tyan 		}
1138*88364387SHung-ying Tyan 	} else if (0 == strcmp("read", cmd)) {
1139*88364387SHung-ying Tyan 		ret = do_read_write(dev, 0, argc, argv);
1140*88364387SHung-ying Tyan 		if (ret > 0)
1141*88364387SHung-ying Tyan 			return CMD_RET_USAGE;
1142*88364387SHung-ying Tyan 	} else if (0 == strcmp("write", cmd)) {
1143*88364387SHung-ying Tyan 		ret = do_read_write(dev, 1, argc, argv);
1144*88364387SHung-ying Tyan 		if (ret > 0)
1145*88364387SHung-ying Tyan 			return CMD_RET_USAGE;
1146*88364387SHung-ying Tyan 	} else if (0 == strcmp("erase", cmd)) {
1147*88364387SHung-ying Tyan 		int region = cros_ec_decode_region(argc - 2, argv + 2);
1148*88364387SHung-ying Tyan 		uint32_t offset, size;
1149*88364387SHung-ying Tyan 
1150*88364387SHung-ying Tyan 		if (region == -1)
1151*88364387SHung-ying Tyan 			return CMD_RET_USAGE;
1152*88364387SHung-ying Tyan 		if (cros_ec_flash_offset(dev, region, &offset, &size)) {
1153*88364387SHung-ying Tyan 			debug("%s: Could not read region info\n", __func__);
1154*88364387SHung-ying Tyan 			ret = -1;
1155*88364387SHung-ying Tyan 		} else {
1156*88364387SHung-ying Tyan 			ret = cros_ec_flash_erase(dev, offset, size);
1157*88364387SHung-ying Tyan 			if (ret) {
1158*88364387SHung-ying Tyan 				debug("%s: Could not erase region\n",
1159*88364387SHung-ying Tyan 				      __func__);
1160*88364387SHung-ying Tyan 			}
1161*88364387SHung-ying Tyan 		}
1162*88364387SHung-ying Tyan 	} else if (0 == strcmp("regioninfo", cmd)) {
1163*88364387SHung-ying Tyan 		int region = cros_ec_decode_region(argc - 2, argv + 2);
1164*88364387SHung-ying Tyan 		uint32_t offset, size;
1165*88364387SHung-ying Tyan 
1166*88364387SHung-ying Tyan 		if (region == -1)
1167*88364387SHung-ying Tyan 			return CMD_RET_USAGE;
1168*88364387SHung-ying Tyan 		ret = cros_ec_flash_offset(dev, region, &offset, &size);
1169*88364387SHung-ying Tyan 		if (ret) {
1170*88364387SHung-ying Tyan 			debug("%s: Could not read region info\n", __func__);
1171*88364387SHung-ying Tyan 		} else {
1172*88364387SHung-ying Tyan 			printf("Region: %s\n", region == EC_FLASH_REGION_RO ?
1173*88364387SHung-ying Tyan 					"RO" : "RW");
1174*88364387SHung-ying Tyan 			printf("Offset: %x\n", offset);
1175*88364387SHung-ying Tyan 			printf("Size:   %x\n", size);
1176*88364387SHung-ying Tyan 		}
1177*88364387SHung-ying Tyan 	} else if (0 == strcmp("vbnvcontext", cmd)) {
1178*88364387SHung-ying Tyan 		uint8_t block[EC_VBNV_BLOCK_SIZE];
1179*88364387SHung-ying Tyan 		char buf[3];
1180*88364387SHung-ying Tyan 		int i, len;
1181*88364387SHung-ying Tyan 		unsigned long result;
1182*88364387SHung-ying Tyan 
1183*88364387SHung-ying Tyan 		if (argc <= 2) {
1184*88364387SHung-ying Tyan 			ret = cros_ec_read_vbnvcontext(dev, block);
1185*88364387SHung-ying Tyan 			if (!ret) {
1186*88364387SHung-ying Tyan 				printf("vbnv_block: ");
1187*88364387SHung-ying Tyan 				for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++)
1188*88364387SHung-ying Tyan 					printf("%02x", block[i]);
1189*88364387SHung-ying Tyan 				putc('\n');
1190*88364387SHung-ying Tyan 			}
1191*88364387SHung-ying Tyan 		} else {
1192*88364387SHung-ying Tyan 			/*
1193*88364387SHung-ying Tyan 			 * TODO(clchiou): Move this to a utility function as
1194*88364387SHung-ying Tyan 			 * cmd_spi might want to call it.
1195*88364387SHung-ying Tyan 			 */
1196*88364387SHung-ying Tyan 			memset(block, 0, EC_VBNV_BLOCK_SIZE);
1197*88364387SHung-ying Tyan 			len = strlen(argv[2]);
1198*88364387SHung-ying Tyan 			buf[2] = '\0';
1199*88364387SHung-ying Tyan 			for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) {
1200*88364387SHung-ying Tyan 				if (i * 2 >= len)
1201*88364387SHung-ying Tyan 					break;
1202*88364387SHung-ying Tyan 				buf[0] = argv[2][i * 2];
1203*88364387SHung-ying Tyan 				if (i * 2 + 1 >= len)
1204*88364387SHung-ying Tyan 					buf[1] = '0';
1205*88364387SHung-ying Tyan 				else
1206*88364387SHung-ying Tyan 					buf[1] = argv[2][i * 2 + 1];
1207*88364387SHung-ying Tyan 				strict_strtoul(buf, 16, &result);
1208*88364387SHung-ying Tyan 				block[i] = result;
1209*88364387SHung-ying Tyan 			}
1210*88364387SHung-ying Tyan 			ret = cros_ec_write_vbnvcontext(dev, block);
1211*88364387SHung-ying Tyan 		}
1212*88364387SHung-ying Tyan 		if (ret) {
1213*88364387SHung-ying Tyan 			debug("%s: Could not %s VbNvContext\n", __func__,
1214*88364387SHung-ying Tyan 					argc <= 2 ?  "read" : "write");
1215*88364387SHung-ying Tyan 		}
1216*88364387SHung-ying Tyan 	} else if (0 == strcmp("test", cmd)) {
1217*88364387SHung-ying Tyan 		int result = cros_ec_test(dev);
1218*88364387SHung-ying Tyan 
1219*88364387SHung-ying Tyan 		if (result)
1220*88364387SHung-ying Tyan 			printf("Test failed with error %d\n", result);
1221*88364387SHung-ying Tyan 		else
1222*88364387SHung-ying Tyan 			puts("Test passed\n");
1223*88364387SHung-ying Tyan 	} else if (0 == strcmp("version", cmd)) {
1224*88364387SHung-ying Tyan 		struct ec_response_get_version *p;
1225*88364387SHung-ying Tyan 		char *build_string;
1226*88364387SHung-ying Tyan 
1227*88364387SHung-ying Tyan 		ret = cros_ec_read_version(dev, &p);
1228*88364387SHung-ying Tyan 		if (!ret) {
1229*88364387SHung-ying Tyan 			/* Print versions */
1230*88364387SHung-ying Tyan 			printf("RO version:    %1.*s\n",
1231*88364387SHung-ying Tyan 			       sizeof(p->version_string_ro),
1232*88364387SHung-ying Tyan 			       p->version_string_ro);
1233*88364387SHung-ying Tyan 			printf("RW version:    %1.*s\n",
1234*88364387SHung-ying Tyan 			       sizeof(p->version_string_rw),
1235*88364387SHung-ying Tyan 			       p->version_string_rw);
1236*88364387SHung-ying Tyan 			printf("Firmware copy: %s\n",
1237*88364387SHung-ying Tyan 				(p->current_image <
1238*88364387SHung-ying Tyan 					ARRAY_SIZE(ec_current_image_name) ?
1239*88364387SHung-ying Tyan 				ec_current_image_name[p->current_image] :
1240*88364387SHung-ying Tyan 				"?"));
1241*88364387SHung-ying Tyan 			ret = cros_ec_read_build_info(dev, &build_string);
1242*88364387SHung-ying Tyan 			if (!ret)
1243*88364387SHung-ying Tyan 				printf("Build info:    %s\n", build_string);
1244*88364387SHung-ying Tyan 		}
1245*88364387SHung-ying Tyan 	} else if (0 == strcmp("ldo", cmd)) {
1246*88364387SHung-ying Tyan 		uint8_t index, state;
1247*88364387SHung-ying Tyan 		char *endp;
1248*88364387SHung-ying Tyan 
1249*88364387SHung-ying Tyan 		if (argc < 3)
1250*88364387SHung-ying Tyan 			return CMD_RET_USAGE;
1251*88364387SHung-ying Tyan 		index = simple_strtoul(argv[2], &endp, 10);
1252*88364387SHung-ying Tyan 		if (*argv[2] == 0 || *endp != 0)
1253*88364387SHung-ying Tyan 			return CMD_RET_USAGE;
1254*88364387SHung-ying Tyan 		if (argc > 3) {
1255*88364387SHung-ying Tyan 			state = simple_strtoul(argv[3], &endp, 10);
1256*88364387SHung-ying Tyan 			if (*argv[3] == 0 || *endp != 0)
1257*88364387SHung-ying Tyan 				return CMD_RET_USAGE;
1258*88364387SHung-ying Tyan 			ret = cros_ec_set_ldo(dev, index, state);
1259*88364387SHung-ying Tyan 		} else {
1260*88364387SHung-ying Tyan 			ret = cros_ec_get_ldo(dev, index, &state);
1261*88364387SHung-ying Tyan 			if (!ret) {
1262*88364387SHung-ying Tyan 				printf("LDO%d: %s\n", index,
1263*88364387SHung-ying Tyan 					state == EC_LDO_STATE_ON ?
1264*88364387SHung-ying Tyan 					"on" : "off");
1265*88364387SHung-ying Tyan 			}
1266*88364387SHung-ying Tyan 		}
1267*88364387SHung-ying Tyan 
1268*88364387SHung-ying Tyan 		if (ret) {
1269*88364387SHung-ying Tyan 			debug("%s: Could not access LDO%d\n", __func__, index);
1270*88364387SHung-ying Tyan 			return ret;
1271*88364387SHung-ying Tyan 		}
1272*88364387SHung-ying Tyan 	} else {
1273*88364387SHung-ying Tyan 		return CMD_RET_USAGE;
1274*88364387SHung-ying Tyan 	}
1275*88364387SHung-ying Tyan 
1276*88364387SHung-ying Tyan 	if (ret < 0) {
1277*88364387SHung-ying Tyan 		printf("Error: CROS-EC command failed (error %d)\n", ret);
1278*88364387SHung-ying Tyan 		ret = 1;
1279*88364387SHung-ying Tyan 	}
1280*88364387SHung-ying Tyan 
1281*88364387SHung-ying Tyan 	return ret;
1282*88364387SHung-ying Tyan }
1283*88364387SHung-ying Tyan 
1284*88364387SHung-ying Tyan U_BOOT_CMD(
1285*88364387SHung-ying Tyan 	crosec,	5,	1,	do_cros_ec,
1286*88364387SHung-ying Tyan 	"CROS-EC utility command",
1287*88364387SHung-ying Tyan 	"init                Re-init CROS-EC (done on startup automatically)\n"
1288*88364387SHung-ying Tyan 	"crosec id                  Read CROS-EC ID\n"
1289*88364387SHung-ying Tyan 	"crosec info                Read CROS-EC info\n"
1290*88364387SHung-ying Tyan 	"crosec curimage            Read CROS-EC current image\n"
1291*88364387SHung-ying Tyan 	"crosec hash                Read CROS-EC hash\n"
1292*88364387SHung-ying Tyan 	"crosec reboot [rw | ro | cold]  Reboot CROS-EC\n"
1293*88364387SHung-ying Tyan 	"crosec events              Read CROS-EC host events\n"
1294*88364387SHung-ying Tyan 	"crosec clrevents [mask]    Clear CROS-EC host events\n"
1295*88364387SHung-ying Tyan 	"crosec regioninfo <ro|rw>  Read image info\n"
1296*88364387SHung-ying Tyan 	"crosec erase <ro|rw>       Erase EC image\n"
1297*88364387SHung-ying Tyan 	"crosec read <ro|rw> <addr> [<size>]   Read EC image\n"
1298*88364387SHung-ying Tyan 	"crosec write <ro|rw> <addr> [<size>]  Write EC image\n"
1299*88364387SHung-ying Tyan 	"crosec vbnvcontext [hexstring]        Read [write] VbNvContext from EC\n"
1300*88364387SHung-ying Tyan 	"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
1301*88364387SHung-ying Tyan 	"crosec test                run tests on cros_ec\n"
1302*88364387SHung-ying Tyan 	"crosec version             Read CROS-EC version"
1303*88364387SHung-ying Tyan );
1304*88364387SHung-ying Tyan #endif
1305