1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Chromium OS cros_ec driver - I2C interface 4 * 5 * Copyright (c) 2012 The Chromium OS Authors. 6 */ 7 8 /* 9 * The Matrix Keyboard Protocol driver handles talking to the keyboard 10 * controller chip. Mostly this is for keyboard functions, but some other 11 * things have slipped in, so we provide generic services to talk to the 12 * KBC. 13 */ 14 15 #include <common.h> 16 #include <dm.h> 17 #include <i2c.h> 18 #include <cros_ec.h> 19 20 #ifdef DEBUG_TRACE 21 #define debug_trace(fmt, b...) debug(fmt, #b) 22 #else 23 #define debug_trace(fmt, b...) 24 #endif 25 26 /** 27 * Request format for protocol v3 28 * byte 0 0xda (EC_COMMAND_PROTOCOL_3) 29 * byte 1-8 struct ec_host_request 30 * byte 10- response data 31 */ 32 struct ec_host_request_i2c { 33 /* Always 0xda to backward compatible with v2 struct */ 34 uint8_t command_protocol; 35 struct ec_host_request ec_request; 36 } __packed; 37 38 /* 39 * Response format for protocol v3 40 * byte 0 result code 41 * byte 1 packet_length 42 * byte 2-9 struct ec_host_response 43 * byte 10- response data 44 */ 45 struct ec_host_response_i2c { 46 uint8_t result; 47 uint8_t packet_length; 48 struct ec_host_response ec_response; 49 } __packed; 50 51 static int cros_ec_i2c_packet(struct udevice *udev, int out_bytes, int in_bytes) 52 { 53 struct cros_ec_dev *dev = dev_get_uclass_priv(udev); 54 struct dm_i2c_chip *chip = dev_get_parent_platdata(udev); 55 struct ec_host_request_i2c *ec_request_i2c = 56 (struct ec_host_request_i2c *)dev->dout; 57 struct ec_host_response_i2c *ec_response_i2c = 58 (struct ec_host_response_i2c *)dev->din; 59 struct i2c_msg i2c_msg[2]; 60 int ret; 61 62 i2c_msg[0].addr = chip->chip_addr; 63 i2c_msg[0].flags = 0; 64 i2c_msg[1].addr = chip->chip_addr; 65 i2c_msg[1].flags = I2C_M_RD; 66 67 /* one extra byte, to indicate v3 */ 68 i2c_msg[0].len = out_bytes + 1; 69 i2c_msg[0].buf = dev->dout; 70 71 /* stitch on EC_COMMAND_PROTOCOL_3 */ 72 memmove(&ec_request_i2c->ec_request, dev->dout, out_bytes); 73 ec_request_i2c->command_protocol = EC_COMMAND_PROTOCOL_3; 74 75 /* two extra bytes for v3 */ 76 i2c_msg[1].len = in_bytes + 2; 77 i2c_msg[1].buf = dev->din; 78 79 ret = dm_i2c_xfer(udev, &i2c_msg[0], 2); 80 if (ret) { 81 printf("%s: Could not execute transfer: %d\n", __func__, ret); 82 return ret; 83 } 84 85 /* When we send a v3 request to v2 ec, ec won't recognize the 0xda 86 * (EC_COMMAND_PROTOCOL_3) and will return with status 87 * EC_RES_INVALID_COMMAND with zero data length 88 * 89 * In case of invalid command for v3 protocol the data length 90 * will be at least sizeof(struct ec_host_response) 91 */ 92 if (ec_response_i2c->result == EC_RES_INVALID_COMMAND && 93 ec_response_i2c->packet_length == 0) 94 return -EPROTONOSUPPORT; 95 96 if (ec_response_i2c->packet_length < sizeof(struct ec_host_response)) { 97 printf("%s: response of %u bytes too short; not a full hdr\n", 98 __func__, ec_response_i2c->packet_length); 99 return -EBADMSG; 100 } 101 102 103 /* drop result and packet_len */ 104 memmove(dev->din, &ec_response_i2c->ec_response, in_bytes); 105 106 return in_bytes; 107 } 108 109 static int cros_ec_i2c_command(struct udevice *udev, uint8_t cmd, 110 int cmd_version, const uint8_t *dout, 111 int dout_len, uint8_t **dinp, int din_len) 112 { 113 struct cros_ec_dev *dev = dev_get_uclass_priv(udev); 114 struct dm_i2c_chip *chip = dev_get_parent_platdata(udev); 115 struct i2c_msg i2c_msg[2]; 116 /* version8, cmd8, arglen8, out8[dout_len], csum8 */ 117 int out_bytes = dout_len + 4; 118 /* response8, arglen8, in8[din_len], checksum8 */ 119 int in_bytes = din_len + 3; 120 uint8_t *ptr; 121 /* Receive input data, so that args will be dword aligned */ 122 uint8_t *in_ptr; 123 int len, csum, ret; 124 125 /* 126 * Sanity-check I/O sizes given transaction overhead in internal 127 * buffers. 128 */ 129 if (out_bytes > sizeof(dev->dout)) { 130 debug("%s: Cannot send %d bytes\n", __func__, dout_len); 131 return -1; 132 } 133 if (in_bytes > sizeof(dev->din)) { 134 debug("%s: Cannot receive %d bytes\n", __func__, din_len); 135 return -1; 136 } 137 assert(dout_len >= 0); 138 assert(dinp); 139 140 i2c_msg[0].addr = chip->chip_addr; 141 i2c_msg[0].len = out_bytes; 142 i2c_msg[0].buf = dev->dout; 143 i2c_msg[0].flags = 0; 144 145 /* 146 * Copy command and data into output buffer so we can do a single I2C 147 * burst transaction. 148 */ 149 ptr = dev->dout; 150 151 /* 152 * in_ptr starts of pointing to a dword-aligned input data buffer. 153 * We decrement it back by the number of header bytes we expect to 154 * receive, so that the first parameter of the resulting input data 155 * will be dword aligned. 156 */ 157 in_ptr = dev->din + sizeof(int64_t); 158 159 if (dev->protocol_version != 2) { 160 /* Something we don't support */ 161 debug("%s: Protocol version %d unsupported\n", 162 __func__, dev->protocol_version); 163 return -1; 164 } 165 166 *ptr++ = EC_CMD_VERSION0 + cmd_version; 167 *ptr++ = cmd; 168 *ptr++ = dout_len; 169 in_ptr -= 2; /* Expect status, length bytes */ 170 171 memcpy(ptr, dout, dout_len); 172 ptr += dout_len; 173 174 *ptr++ = (uint8_t) 175 cros_ec_calc_checksum(dev->dout, dout_len + 3); 176 177 i2c_msg[1].addr = chip->chip_addr; 178 i2c_msg[1].len = in_bytes; 179 i2c_msg[1].buf = in_ptr; 180 i2c_msg[1].flags = I2C_M_RD; 181 182 /* Send output data */ 183 cros_ec_dump_data("out", -1, dev->dout, out_bytes); 184 185 ret = dm_i2c_xfer(udev, &i2c_msg[0], 2); 186 if (ret) { 187 debug("%s: Could not execute transfer to %s\n", __func__, 188 udev->name); 189 ret = -1; 190 } 191 192 if (*in_ptr != EC_RES_SUCCESS) { 193 debug("%s: Received bad result code %d\n", __func__, *in_ptr); 194 return -(int)*in_ptr; 195 } 196 197 len = in_ptr[1]; 198 if (len + 3 > sizeof(dev->din)) { 199 debug("%s: Received length %#02x too large\n", 200 __func__, len); 201 return -1; 202 } 203 csum = cros_ec_calc_checksum(in_ptr, 2 + len); 204 if (csum != in_ptr[2 + len]) { 205 debug("%s: Invalid checksum rx %#02x, calced %#02x\n", 206 __func__, in_ptr[2 + din_len], csum); 207 return -1; 208 } 209 din_len = min(din_len, len); 210 cros_ec_dump_data("in", -1, in_ptr, din_len + 3); 211 212 /* Return pointer to dword-aligned input data, if any */ 213 *dinp = dev->din + sizeof(int64_t); 214 215 return din_len; 216 } 217 218 static int cros_ec_probe(struct udevice *dev) 219 { 220 return cros_ec_register(dev); 221 } 222 223 static struct dm_cros_ec_ops cros_ec_ops = { 224 .command = cros_ec_i2c_command, 225 .packet = cros_ec_i2c_packet, 226 }; 227 228 static const struct udevice_id cros_ec_ids[] = { 229 { .compatible = "google,cros-ec-i2c" }, 230 { } 231 }; 232 233 U_BOOT_DRIVER(cros_ec_i2c) = { 234 .name = "cros_ec_i2c", 235 .id = UCLASS_CROS_EC, 236 .of_match = cros_ec_ids, 237 .probe = cros_ec_probe, 238 .ops = &cros_ec_ops, 239 }; 240