cros_ec_i2c.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2012 Google Inc.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * Neither the name of Google or the names of contributors or
  18. * licensors may be used to endorse or promote products derived from this
  19. * software without specific prior written permission.
  20. *
  21. * This software is provided "AS IS," without a warranty of any kind.
  22. * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
  23. * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
  24. * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
  25. * GOOGLE INC AND ITS LICENSORS SHALL NOT BE LIABLE
  26. * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  27. * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
  28. * GOOGLE OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
  29. * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
  30. * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
  31. * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
  32. * EVEN IF GOOGLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  33. */
  34. #include <inttypes.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include "file.h"
  39. #include "flash.h"
  40. #if USE_CROS_EC_LOCK == 1
  41. #include "cros_ec_lock.h"
  42. #endif
  43. #include "cros_ec_commands.h"
  44. #include "programmer.h"
  45. #include "cros_ec.h"
  46. #define SYSFS_I2C_DEV_ROOT "/sys/bus/i2c/devices"
  47. #define CROS_EC_I2C_DEVICE_NAME1 "cros-ec-i2c" /* upstream name */
  48. #define CROS_EC_I2C_DEVICE_NAME2 "chromeos-ec-i2c" /* 3.4 name */
  49. #define CROS_EC_I2C_ADDRESS 0x1e
  50. /* v2 protocol bytes
  51. * OUT: (version, command, size, ... request ..., checksum) */
  52. #define CROS_EC_PROTO_BYTES_V2_OUT 4
  53. /* IN: (command, size, ... response ..., checkcum) */
  54. #define CROS_EC_PROTO_BYTES_V2_IN 3
  55. /*
  56. * Flash erase on a 1024 byte chunk takes about 22.05ms on STM32-based CROS_EC.
  57. * We'll leave about a half millisecond extra for other overhead to avoid
  58. * polling the status too aggressively.
  59. *
  60. * TODO: determine better delay value or mechanism for all chips and commands.
  61. */
  62. #define STM32_ERASE_DELAY 22500 /* 22.5ms */
  63. #define CROS_EC_COMMAND_RETRIES 5
  64. #define CROS_EC_LOCK_TIMEOUT_SECS 30 /* 30 secs */
  65. static int ec_timeout_usec = 1000000;
  66. static unsigned int bus;
  67. static int cros_ec_i2c_shutdown(void *data)
  68. {
  69. #if USE_CROS_EC_LOCK == 1
  70. release_cros_ec_lock();
  71. #endif
  72. return linux_i2c_shutdown(data);
  73. }
  74. void delay_for_command(int command)
  75. {
  76. switch (command) {
  77. case EC_CMD_FLASH_ERASE:
  78. programmer_delay(STM32_ERASE_DELAY);
  79. break;
  80. default:
  81. break;
  82. }
  83. }
  84. /* returns 0 if command is successful, <0 to indicate timeout or error */
  85. static int command_response(int command, int version, uint8_t response_code)
  86. {
  87. uint8_t *status_cmd;
  88. struct ec_response_get_comms_status status;
  89. int i, status_cmd_len, ret = -EC_RES_TIMEOUT;
  90. int csum;
  91. if (response_code != EC_RES_IN_PROGRESS)
  92. return -response_code;
  93. status_cmd_len = CROS_EC_PROTO_BYTES_V2_OUT;
  94. status_cmd = malloc(status_cmd_len);
  95. status_cmd[0] = EC_CMD_VERSION0 + version;
  96. status_cmd[1] = EC_CMD_GET_COMMS_STATUS;
  97. status_cmd[2] = 0;
  98. csum = status_cmd[0] + status_cmd[1] + status_cmd[2];
  99. status_cmd[3] = csum & 0xff;
  100. for (i = 1; i <= CROS_EC_COMMAND_RETRIES; i++) {
  101. /*
  102. * The first retry might work practically immediately, so
  103. * skip the delay for the first retry.
  104. */
  105. if (i != 1)
  106. delay_for_command(command);
  107. msg_pspew("retry %d / %d\n", i, CROS_EC_COMMAND_RETRIES);
  108. ret = linux_i2c_xfer(bus, CROS_EC_I2C_ADDRESS,
  109. &status, sizeof(status),
  110. status_cmd, status_cmd_len);
  111. if (ret) {
  112. msg_perr("%s(): linux_i2c_xfer() failed: %d\n",
  113. __func__, ret);
  114. ret = -EC_RES_ERROR;
  115. break;
  116. }
  117. if (!(status.flags & EC_COMMS_STATUS_PROCESSING)) {
  118. ret = -EC_RES_SUCCESS;
  119. break;
  120. }
  121. }
  122. free(status_cmd);
  123. return ret;
  124. }
  125. /*
  126. * cros_ec_command_i2c - (protocol v2) Issue command to CROS_EC over I2C
  127. *
  128. * @command: command code
  129. * @outdata: data to send to EC
  130. * @outsize: number of bytes in outbound payload
  131. * @indata: (unallocated) buffer to store data received from EC
  132. * @insize: number of bytes in inbound payload
  133. *
  134. * Protocol-related details will be handled by this function. The outdata
  135. * and indata buffers will contain payload data (if any); command and response
  136. * codes as well as checksum data are handled transparently by this function.
  137. *
  138. * Returns >=0 for success, or negative if other error.
  139. */
  140. static int cros_ec_command_i2c(int command, int version,
  141. const void *outdata, int outsize,
  142. void *indata, int insize) {
  143. int ret = -1;
  144. uint8_t *req_buf = NULL, *resp_buf = NULL;
  145. int req_len = 0, resp_len = 0;
  146. int i, csum;
  147. if (version > 1) {
  148. msg_perr("%s() version >1 not supported yet.\n", __func__);
  149. return -EC_RES_INVALID_VERSION;
  150. }
  151. req_len = outsize + CROS_EC_PROTO_BYTES_V2_OUT;
  152. req_buf = calloc(1, req_len);
  153. if (!req_buf)
  154. goto done;
  155. req_buf[0] = version + EC_CMD_VERSION0;
  156. req_buf[1] = command;
  157. req_buf[2] = outsize;
  158. csum = req_buf[0] + req_buf[1] + req_buf[2];
  159. /* copy message payload and compute checksum */
  160. memcpy(&req_buf[3], outdata, outsize);
  161. for (i = 0; i < outsize; i++) {
  162. csum += *((uint8_t *)outdata + i);
  163. }
  164. req_buf[req_len - 1] = csum & 0xff;
  165. msg_pspew("%s: req_buf: ", __func__);
  166. for (i = 0; i < req_len; i++)
  167. msg_pspew("%02x ", req_buf[i]);
  168. msg_pspew("\n");
  169. resp_len = insize + CROS_EC_PROTO_BYTES_V2_IN;
  170. resp_buf = calloc(1, resp_len);
  171. if (!resp_buf)
  172. goto done;
  173. ret = linux_i2c_xfer(bus, CROS_EC_I2C_ADDRESS,
  174. resp_buf, resp_len, req_buf, req_len);
  175. if (ret) {
  176. msg_perr("%s(): linux_i2c_xfer() failed: %d\n", __func__, ret);
  177. ret = -EC_RES_ERROR;
  178. goto done;
  179. }
  180. msg_pspew("%s: resp_buf: ", __func__);
  181. for (i = 0; i < resp_len; i++)
  182. msg_pspew("%02x ", resp_buf[i]);
  183. msg_pspew("\n");
  184. ret = command_response(command, version, resp_buf[0]);
  185. if (ret) {
  186. msg_pdbg("command 0x%02x returned an error %d\n", command, ret);
  187. goto done;
  188. }
  189. resp_len = resp_buf[1];
  190. if (resp_len > insize) {
  191. msg_perr("%s(): responsed size is too large %d > %d\n",
  192. __func__, resp_len, insize);
  193. ret = -EC_RES_ERROR;
  194. goto done;
  195. }
  196. if (insize) {
  197. /* copy response packet payload and compute checksum */
  198. csum = resp_buf[0] + resp_buf[1];
  199. for (i = 0; i < resp_len; i++)
  200. csum += resp_buf[i + 2];
  201. csum &= 0xff;
  202. if (csum != resp_buf[resp_len + 2]) {
  203. msg_pdbg("bad checksum (got 0x%02x from EC, calculated "
  204. "0x%02x\n", resp_buf[resp_len + 2], csum);
  205. ret = -EC_RES_INVALID_CHECKSUM;
  206. goto done;
  207. }
  208. memcpy(indata, &resp_buf[2], resp_len);
  209. }
  210. ret = resp_len;
  211. done:
  212. if (resp_buf)
  213. free(resp_buf);
  214. if (req_buf)
  215. free(req_buf);
  216. return ret;
  217. }
  218. static struct cros_ec_priv cros_ec_i2c_priv = {
  219. .detected = 0,
  220. .ec_command = cros_ec_command_i2c,
  221. };
  222. static struct opaque_programmer opaque_programmer_cros_ec_i2c = {
  223. /* These should be EC_PROTO2_MAX_PARAM_SIZE but for now we
  224. * use values from earlier on to be safe. */
  225. .max_data_read = 128,
  226. .max_data_write = EC_FLASH_WRITE_VER0_SIZE,
  227. .probe = cros_ec_probe_size,
  228. .read = cros_ec_read,
  229. .write = cros_ec_write,
  230. .erase = cros_ec_block_erase,
  231. };
  232. int cros_ec_probe_i2c(const char *name)
  233. {
  234. const char *path, *s;
  235. int ret = 1;
  236. int old_timeout = ec_timeout_usec;
  237. if (alias && alias->type != ALIAS_EC)
  238. return 1;
  239. if (cros_ec_parse_param(&cros_ec_i2c_priv))
  240. return 1;
  241. if (cros_ec_i2c_priv.dev && strcmp(cros_ec_i2c_priv.dev, "ec")) {
  242. msg_pdbg("cros_ec_i2c only supports \"ec\" type devices.\n");
  243. return 1;
  244. }
  245. #if USE_CROS_EC_LOCK == 1
  246. if (acquire_cros_ec_lock(CROS_EC_LOCK_TIMEOUT_SECS) < 0) {
  247. msg_gerr("Could not acquire CROS_EC lock.\n");
  248. return 1;
  249. }
  250. #endif
  251. msg_pdbg("%s: probing for CROS_EC on I2C...\n", __func__);
  252. /*
  253. * We look for the device using two possible names (since the EC landed
  254. * upstream with a different name than the ChromeOS 3.4 kernel).
  255. */
  256. path = scanft(SYSFS_I2C_DEV_ROOT, "name", CROS_EC_I2C_DEVICE_NAME1, 1);
  257. if (!path) {
  258. path = scanft(SYSFS_I2C_DEV_ROOT, "name", CROS_EC_I2C_DEVICE_NAME2,
  259. 1);
  260. if (!path) {
  261. msg_pdbg("CROS_EC I2C device not found\n");
  262. goto cros_ec_probe_i2c_done;
  263. }
  264. }
  265. /*
  266. * i2c-* may show up more than once in the path (especially in the
  267. * case of the MFD with passthru I2C adapter), so use whichever
  268. * instance shows up last.
  269. */
  270. for (s = path + strlen(path) - 4; s > path; s--) {
  271. if (!strncmp(s, "i2c-", 4))
  272. break;
  273. }
  274. if ((s == path) || (sscanf(s, "i2c-%u", &bus) != 1)) {
  275. msg_perr("Unable to parse I2C bus number\n");
  276. goto cros_ec_probe_i2c_done;
  277. }
  278. msg_pdbg("Opening CROS_EC (bus %u, addr 0x%02x)\n", bus, CROS_EC_I2C_ADDRESS);
  279. if (linux_i2c_open(bus, CROS_EC_I2C_ADDRESS, 1))
  280. goto cros_ec_probe_i2c_done;
  281. /* reduce timeout period temporarily in case EC is not present */
  282. ec_timeout_usec = 25000;
  283. if (cros_ec_test(&cros_ec_i2c_priv)) {
  284. linux_i2c_close();
  285. goto cros_ec_probe_i2c_done;
  286. }
  287. if (register_shutdown(cros_ec_i2c_shutdown, NULL))
  288. goto cros_ec_probe_i2c_done;
  289. cros_ec_set_max_size(&cros_ec_i2c_priv, &opaque_programmer_cros_ec_i2c);
  290. msg_pdbg("CROS_EC detected on I2C bus\n");
  291. register_opaque_programmer(&opaque_programmer_cros_ec_i2c);
  292. cros_ec_i2c_priv.detected = 1;
  293. cros_ec_priv = &cros_ec_i2c_priv;
  294. ret = 0;
  295. cros_ec_probe_i2c_done:
  296. ec_timeout_usec = old_timeout;
  297. free((void*)path);
  298. return ret;
  299. }