blob: eca1eb9b4d07cad502b892920057ca39d39d2a2e [file] [log] [blame]
Hung-Te Lin6bfbb332013-04-15 18:27:24 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Hung-Te Lin6bfbb332013-04-15 18:27:24 +080014 */
15
16#include <arch/io.h>
17#include <console/console.h>
18#include <delay.h>
19#include <device/i2c.h>
20#include <stdint.h>
21#include <string.h>
Edward O'Callaghanb57fef92014-06-17 20:13:08 +100022
Hung-Te Lin6bfbb332013-04-15 18:27:24 +080023#include "ec.h"
24#include "ec_commands.h"
25
Aaron Durbinaee78f02014-08-06 14:38:52 -050026#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC_I2C_PROTO3)
27
28#define PROTO3_FRAMING_BYTES sizeof(uint32_t)
29/* Just use the LPC host packet size to size the buffer. */
30#define PROTO3_MAX_PACKET_SIZE 268
31
32struct proto3_i2c_buf {
33 uint8_t framing_bytes[PROTO3_FRAMING_BYTES];
34 uint8_t data[PROTO3_MAX_PACKET_SIZE];
35} __attribute__((aligned(sizeof(uint32_t))));
36
37static struct proto3_i2c_buf req_buf;
38static struct proto3_i2c_buf resp_buf;
39
40enum {
41 CMD_INDEX,
42 RESP_INDEX,
43 SEGS_PER_CMD,
44};
45
46struct i2c_ec {
47 int bus;
48 struct i2c_seg segs[SEGS_PER_CMD];
49};
50
51static struct i2c_ec ec_dev = {
52 .bus = CONFIG_EC_GOOGLE_CHROMEEC_I2C_BUS,
53 .segs[CMD_INDEX] = {
54 .read = 0,
55 .chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP,
56 /* Framing byte to be transferred prior to request. */
57 .buf = &req_buf.framing_bytes[3],
58 },
59 .segs[RESP_INDEX] = {
60 .read = 1,
61 .chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP,
62 /* return code and total length before full response. */
63 .buf = &resp_buf.framing_bytes[2],
64 },
65};
66
67void *crosec_get_buffer(size_t size, int req)
68{
69 struct proto3_i2c_buf *ib;
70
71 if (size > PROTO3_MAX_PACKET_SIZE) {
72 printk(BIOS_DEBUG, "Proto v3 buffer request too large: %zu!\n",
73 size);
74 return NULL;
75 }
76
77 if (req)
78 ib = &req_buf;
79 else
80 ib = &resp_buf;
81
82 return &ib->data[0];
83}
84
85static int crosec_i2c_io(size_t req_size, size_t resp_size, void *context)
86{
87 struct i2c_ec *ec = context;
88 uint8_t ret_code;
89 size_t resp_len;
90
91 if (req_size > PROTO3_MAX_PACKET_SIZE ||
92 resp_size > PROTO3_MAX_PACKET_SIZE)
93 return -1;
94
95 /* Place the framing byte and set size accordingly. */
96 ec->segs[CMD_INDEX].len = req_size + 1;
97 ec->segs[CMD_INDEX].buf[0] = EC_COMMAND_PROTOCOL_3;
98 /* Return code and length returned prior to packet data. */
99 ec->segs[RESP_INDEX].len = resp_size + 2;
100
101 if (i2c_transfer(ec->bus, ec->segs, ARRAY_SIZE(ec->segs)) != 0) {
102 printk(BIOS_ERR, "%s: Cannot complete read from i2c-%d:%#x\n",
103 __func__, ec->bus, ec->segs[0].chip);
104 return -1;
105 }
106
107 ret_code = ec->segs[RESP_INDEX].buf[0];
108 resp_len = ec->segs[RESP_INDEX].buf[1];
109
110 if (ret_code != 0) {
111 printk(BIOS_ERR, "EC command returned 0x%x\n", ret_code);
112 return -1;
113 }
114
115 if (resp_len > resp_size) {
116 printk(BIOS_ERR, "Response length mismatch %zu vs %zu\n",
117 resp_len, resp_size);
118 return -1;
119 }
120
121 return 0;
122}
123
124int google_chromeec_command(struct chromeec_command *cec_command)
125{
126 return crosec_command_proto(cec_command, crosec_i2c_io, &ec_dev);
127}
128
129#else /* CONFIG_EC_GOOGLE_CHROMEEC_I2C_PROTO3 */
130
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800131/* Command (host->device) format for I2C:
132 * uint8_t version, cmd, len, data[len], checksum;
133 *
134 * Response (device->host) format for I2C:
135 * uint8_t response, len, data[len], checksum;
136 *
137 * Note the location of checksum is different from LPC protocol.
138 *
139 * The length is 8 bit so maximum data size is 0xff.
140 * Any I2C command should fit in 0xff + 4 bytes, and max response length
141 * is 0xff + 3 bytes.
142 */
143#define MAX_I2C_DATA_SIZE (0xff)
144
145typedef struct {
146 uint8_t version;
147 uint8_t command;
148 uint8_t length;
149 uint8_t data[MAX_I2C_DATA_SIZE + 1];
150} EcCommandI2c;
151
152typedef struct {
153 uint8_t response;
154 uint8_t length;
155 uint8_t data[MAX_I2C_DATA_SIZE + 1];
156} EcResponseI2c;
157
158static inline void i2c_dump(int bus, int chip, const uint8_t *data, size_t size)
159{
160#ifdef TRACE_CHROMEEC
161 printk(BIOS_INFO, "i2c: bus=%d, chip=%#x, size=%d, data: ", bus, chip,
162 size);
163 while (size-- > 0) {
164 printk(BIOS_INFO, "%02X ", *data++);
165 }
166 printk(BIOS_INFO, "\n");
167#endif
168}
169
170static int ec_verify_checksum(const EcResponseI2c *resp)
171{
172 size_t size = sizeof(*resp) - sizeof(resp->data) + resp->length;
173 uint8_t calculated = google_chromeec_calc_checksum(
174 (const uint8_t *)resp, size);
175 uint8_t received = resp->data[resp->length];
176 if (calculated != received) {
177 printk(BIOS_ERR, "%s: Unmatch (rx: %#02x, calc: %#02x)\n",
178 __func__, received, calculated);
179 return 0;
180 }
181 return 1;
182}
183
184static void ec_fill_checksum(EcCommandI2c *cmd)
185{
186 size_t size = sizeof(*cmd) - sizeof(cmd->data) + cmd->length;
187 cmd->data[cmd->length] = google_chromeec_calc_checksum(
188 (const uint8_t *)cmd, size);
189}
190
191int google_chromeec_command(struct chromeec_command *cec_command)
192{
193 EcCommandI2c cmd;
194 EcResponseI2c resp;
195 int bus = CONFIG_EC_GOOGLE_CHROMEEC_I2C_BUS;
196 int chip = CONFIG_EC_GOOGLE_CHROMEEC_I2C_CHIP;
197 size_t size_i2c_cmd = (sizeof(cmd) - sizeof(cmd.data) +
198 cec_command->cmd_size_in + 1),
199 size_i2c_resp = (sizeof(resp) - sizeof(resp.data) +
200 cec_command->cmd_size_out + 1);
201
202 if (cec_command->cmd_size_in > MAX_I2C_DATA_SIZE ||
203 cec_command->cmd_size_out > MAX_I2C_DATA_SIZE) {
204 printk(BIOS_ERR, "%s: Command data size too large (%d,%d)\n",
205 __func__, cec_command->cmd_size_in,
206 cec_command->cmd_size_out);
207 cec_command->cmd_code = EC_RES_INVALID_PARAM;
208 return 1;
209 }
210
211 /* Construct command. */
212 cmd.version = EC_CMD_VERSION0 + cec_command->cmd_version;
213 cmd.command = cec_command->cmd_code;
214 cmd.length = cec_command->cmd_size_in;
215 memcpy(cmd.data, cec_command->cmd_data_in, cmd.length);
216 ec_fill_checksum(&cmd);
217
218 /* Start I2C communication */
219 i2c_dump(bus, chip, (const uint8_t *)&cmd, size_i2c_cmd);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700220 if (i2c_write_raw(bus, chip, (uint8_t *)&cmd, size_i2c_cmd) != 0) {
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800221 printk(BIOS_ERR, "%s: Cannot complete write to i2c-%d:%#x\n",
222 __func__, bus, chip);
223 cec_command->cmd_code = EC_RES_ERROR;
224 return 1;
225 }
Gabe Blackcdb61a62014-04-07 18:45:14 -0700226 if (i2c_read_raw(bus, chip, (uint8_t *)&resp, size_i2c_resp) != 0) {
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800227 printk(BIOS_ERR, "%s: Cannot complete read from i2c-%d:%#x\n",
228 __func__, bus, chip);
229 cec_command->cmd_code = EC_RES_ERROR;
230 return 1;
231 }
232
233 /* Verify and return response */
234 cec_command->cmd_code = resp.response;
235 if (resp.response != EC_RES_SUCCESS) {
236 printk(BIOS_DEBUG, "%s: Received bad result code %d\n",
237 __func__, (int)resp.response);
238 return 1;
239 }
240 if (resp.length > cec_command->cmd_size_out) {
241 printk(BIOS_ERR, "%s: Received len %#02x too large\n",
242 __func__, (int)resp.length);
243 cec_command->cmd_code = EC_RES_INVALID_RESPONSE;
244 return 1;
245 }
246 if (!ec_verify_checksum(&resp)) {
247 cec_command->cmd_code = EC_RES_INVALID_CHECKSUM;
248 return 1;
249 }
250 cec_command->cmd_size_out = resp.length;
251 memcpy(cec_command->cmd_data_out, resp.data, resp.length);
252 return 0;
253}
254
Aaron Durbinaee78f02014-08-06 14:38:52 -0500255#endif /* CONFIG_EC_GOOGLE_CHROMEEC_I2C_PROTO3 */
256
Hung-Te Lin6bfbb332013-04-15 18:27:24 +0800257#ifndef __PRE_RAM__
258u8 google_chromeec_get_event(void)
259{
260 printk(BIOS_ERR, "%s: Not supported.\n", __func__);
261 return 0;
262}
263#endif