cros_ec_lpc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /*
  2. * This file is part of the flashrom project.
  3. *
  4. * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
  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 <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <sys/param.h>
  38. #include <unistd.h>
  39. #include "flashchips.h"
  40. #include "fmap.h"
  41. #if USE_CROS_EC_LOCK == 1
  42. #include "cros_ec_lock.h"
  43. #endif
  44. #include "cros_ec_commands.h"
  45. #include "programmer.h"
  46. #include "cros_ec.h"
  47. #include "spi.h"
  48. #include "writeprotect.h"
  49. #define INITIAL_UDELAY 10 /* 10 us */
  50. #define MAXIMUM_UDELAY 10000 /* 10 ms */
  51. static int ec_timeout_usec = 1000000;
  52. #define CROS_EC_LOCK_TIMEOUT_SECS 30 /* 30 secs */
  53. /*
  54. * Wait for the EC to be unbusy. Returns 0 if unbusy, non-zero if
  55. * timeout.
  56. */
  57. static int wait_for_ec(int status_addr, int timeout_usec)
  58. {
  59. int i;
  60. int delay = INITIAL_UDELAY;
  61. for (i = 0; i < timeout_usec; i += delay) {
  62. /*
  63. * Delay first, in case we just sent out a command but the EC
  64. * hasn't raise the busy flag. However, I think this doesn't
  65. * happen since the LPC commands are executed in order and the
  66. * busy flag is set by hardware.
  67. *
  68. * TODO: move this delay after inb(status).
  69. */
  70. usleep(MIN(delay, timeout_usec - i));
  71. if (!(inb(status_addr) & EC_LPC_STATUS_BUSY_MASK))
  72. return 0;
  73. /* Increase the delay interval after a few rapid checks */
  74. if (i > 20)
  75. delay = MIN(delay * 2, MAXIMUM_UDELAY);
  76. }
  77. return -1; /* Timeout */
  78. }
  79. /*
  80. **************************** EC API v0 ****************************
  81. */
  82. /* preserve legacy naming to be consistent with legacy implementation. */
  83. #define EC_LPC_ADDR_OLD_PARAM EC_HOST_CMD_REGION1
  84. #define EC_OLD_PARAM_SIZE EC_HOST_CMD_REGION_SIZE
  85. static enum ec_status cros_ec_get_result() {
  86. return inb(EC_LPC_ADDR_HOST_DATA);
  87. }
  88. /* Sends a command to the EC. Returns the command status code, or
  89. * -1 if other error. */
  90. static int cros_ec_command_lpc_old(int command, int version,
  91. const void *outdata, int outsize,
  92. void *indata, int insize) {
  93. uint8_t *d;
  94. int i;
  95. if ((outsize > EC_OLD_PARAM_SIZE) ||
  96. (insize > EC_OLD_PARAM_SIZE)) {
  97. msg_pdbg2("Data size too big for buffer.\n");
  98. return -EC_RES_INVALID_PARAM;
  99. }
  100. if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, ec_timeout_usec)) {
  101. msg_pdbg2("Timeout waiting for EC ready\n");
  102. return -EC_RES_ERROR;
  103. }
  104. /* Write data, if any */
  105. /* TODO: optimized copy using outl() */
  106. for (i = 0, d = (uint8_t *)outdata; i < outsize; i++, d++) {
  107. msg_pdbg2("CROS_EC: Port[0x%x] <-- 0x%x\n",
  108. EC_LPC_ADDR_OLD_PARAM + i, *d);
  109. outb(*d, EC_LPC_ADDR_OLD_PARAM + i);
  110. }
  111. msg_pdbg2("CROS_EC: Run EC Command: 0x%x ----\n", command);
  112. outb(command, EC_LPC_ADDR_HOST_CMD);
  113. if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, ec_timeout_usec)) {
  114. msg_pdbg2("Timeout waiting for EC response\n");
  115. return -EC_RES_ERROR;
  116. }
  117. /* Check status */
  118. if ((i = cros_ec_get_result()) != EC_RES_SUCCESS) {
  119. msg_pdbg2("EC returned error status %d\n", i);
  120. return -i;
  121. }
  122. /* Read data, if any */
  123. for (i = 0, d = (uint8_t *)indata; i < insize; i++, d++) {
  124. *d = inb(EC_LPC_ADDR_OLD_PARAM + i);
  125. msg_pdbg2("CROS_EC: Port[0x%x] ---> 0x%x\n",
  126. EC_LPC_ADDR_OLD_PARAM + i, *d);
  127. }
  128. return 0;
  129. }
  130. /*
  131. **************************** EC API v2 ****************************
  132. */
  133. static int cros_ec_command_lpc(int command, int version,
  134. const void *outdata, int outsize,
  135. void *indata, int insize,
  136. int (*read_memmap)(uint16_t, uint8_t *),
  137. int (*write_memmap)(uint8_t, uint16_t)) {
  138. struct ec_lpc_host_args args;
  139. const uint8_t *dout;
  140. uint8_t *din;
  141. int csum;
  142. int i;
  143. /* Fill in args */
  144. args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
  145. args.command_version = version;
  146. args.data_size = outsize;
  147. /* Calculate checksum */
  148. csum = command + args.flags + args.command_version + args.data_size;
  149. for (i = 0, dout = (const uint8_t *)outdata; i < outsize; i++, dout++)
  150. csum += *dout;
  151. args.checksum = (uint8_t)csum;
  152. /* Wait EC is ready to accept command before writing anything to
  153. * parameter.
  154. */
  155. if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, ec_timeout_usec)) {
  156. msg_pdbg("Timeout waiting for EC ready\n");
  157. return -EC_RES_ERROR;
  158. }
  159. /* Write args */
  160. for (i = 0, dout = (const uint8_t *)&args;
  161. i < sizeof(args);
  162. i++, dout++)
  163. if (write_memmap(*dout, EC_LPC_ADDR_HOST_ARGS + i))
  164. return -EC_RES_ERROR;
  165. /* Write data, if any */
  166. /* TODO: optimized copy using outl() */
  167. for (i = 0, dout = (uint8_t *)outdata; i < outsize; i++, dout++)
  168. if (write_memmap(*dout, EC_LPC_ADDR_HOST_PARAM + i))
  169. return -EC_RES_ERROR;
  170. outb(command, EC_LPC_ADDR_HOST_CMD);
  171. if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, ec_timeout_usec)) {
  172. msg_perr("Timeout waiting for EC response\n");
  173. return -EC_RES_ERROR;
  174. }
  175. /* Check result */
  176. i = inb(EC_LPC_ADDR_HOST_DATA);
  177. if (i) {
  178. msg_pdbg2("EC returned error result code %d\n", i);
  179. return -i;
  180. }
  181. /* Read back args */
  182. for (i = 0, din = (uint8_t *)&args; i < sizeof(args); i++, din++)
  183. if (read_memmap(EC_LPC_ADDR_HOST_ARGS + i, din))
  184. return -EC_RES_ERROR;
  185. /*
  186. * If EC didn't modify args flags, then somehow we sent a new-style
  187. * command to an old EC, which means it would have read its params
  188. * from the wrong place.
  189. */
  190. if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) {
  191. msg_perr("EC protocol mismatch\n");
  192. return -EC_RES_INVALID_RESPONSE;
  193. }
  194. if (args.data_size > insize) {
  195. msg_perr("EC returned too much data\n");
  196. return -EC_RES_INVALID_RESPONSE;
  197. }
  198. /* Read data, if any */
  199. /* TODO: optimized copy using outl() */
  200. for (i = 0, din = (uint8_t *)indata; i < args.data_size; i++, din++)
  201. if (read_memmap(EC_LPC_ADDR_HOST_PARAM + i, din))
  202. return -EC_RES_ERROR;
  203. /* Verify checksum */
  204. csum = command + args.flags + args.command_version + args.data_size;
  205. for (i = 0, din = (uint8_t *)indata; i < args.data_size; i++, din++)
  206. csum += *din;
  207. if (args.checksum != (uint8_t)csum) {
  208. msg_perr("EC response has invalid checksum\n");
  209. return -EC_RES_INVALID_CHECKSUM;
  210. }
  211. /* Return actual amount of data received */
  212. return args.data_size;
  213. }
  214. /*
  215. **************************** EC API v3 ****************************
  216. */
  217. static int cros_ec_command_lpc_v3(int command, int version,
  218. const void *outdata, int outsize,
  219. void *indata, int insize,
  220. int (*read_memmap)(uint16_t, uint8_t *),
  221. int (*write_memmap)(uint8_t, uint16_t)) {
  222. struct ec_host_request rq;
  223. struct ec_host_response rs;
  224. const uint8_t *d;
  225. uint8_t *dout;
  226. int csum = 0;
  227. int i;
  228. /* Fail if output size is too big */
  229. if (outsize + sizeof(rq) > EC_LPC_HOST_PACKET_SIZE)
  230. return -EC_RES_REQUEST_TRUNCATED;
  231. /* Fill in request packet */
  232. /* TODO(crosbug.com/p/23825): This should be common to all protocols */
  233. rq.struct_version = EC_HOST_REQUEST_VERSION;
  234. rq.checksum = 0;
  235. rq.command = command;
  236. rq.command_version = version;
  237. rq.reserved = 0;
  238. rq.data_len = outsize;
  239. /* Copy data and start checksum */
  240. for (i = 0, d = (const uint8_t *)outdata; i < outsize; i++, d++) {
  241. if (write_memmap(*d, EC_LPC_ADDR_HOST_PACKET + sizeof(rq) + i))
  242. return -EC_RES_ERROR;
  243. csum += *d;
  244. }
  245. /* Finish checksum */
  246. for (i = 0, d = (const uint8_t *)&rq; i < sizeof(rq); i++, d++)
  247. csum += *d;
  248. /* Write checksum field so the entire packet sums to 0 */
  249. rq.checksum = (uint8_t)(-csum);
  250. /* Copy header */
  251. for (i = 0, d = (const uint8_t *)&rq; i < sizeof(rq); i++, d++)
  252. if (write_memmap(*d, EC_LPC_ADDR_HOST_PACKET + i))
  253. return -EC_RES_ERROR;
  254. /* Start the command */
  255. outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD);
  256. if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, ec_timeout_usec)) {
  257. msg_perr("Timeout waiting for EC response\n");
  258. return -EC_RES_ERROR;
  259. }
  260. /* Check result */
  261. i = inb(EC_LPC_ADDR_HOST_DATA);
  262. if (i) {
  263. msg_perr("EC returned error result code %d\n", i);
  264. return -i;
  265. }
  266. /* Read back response header and start checksum */
  267. csum = 0;
  268. for (i = 0, dout = (uint8_t *)&rs; i < sizeof(rs); i++, dout++) {
  269. if (read_memmap(EC_LPC_ADDR_HOST_PACKET + i, dout))
  270. return -EC_RES_ERROR;
  271. csum += *dout;
  272. }
  273. if (rs.struct_version != EC_HOST_RESPONSE_VERSION) {
  274. msg_perr("EC response version mismatch\n");
  275. return -EC_RES_INVALID_RESPONSE;
  276. }
  277. if (rs.reserved) {
  278. msg_perr("EC response reserved != 0\n");
  279. return -EC_RES_INVALID_RESPONSE;
  280. }
  281. if (rs.data_len > insize) {
  282. msg_perr("EC returned too much data\n");
  283. return -EC_RES_RESPONSE_TOO_BIG;
  284. }
  285. /* Read back data and update checksum */
  286. for (i = 0, dout = (uint8_t *)indata; i < rs.data_len; i++, dout++) {
  287. if (read_memmap(EC_LPC_ADDR_HOST_PACKET + sizeof(rs) + i, dout))
  288. return -EC_RES_ERROR;
  289. csum += *dout;
  290. }
  291. /* Verify checksum */
  292. if ((uint8_t)csum) {
  293. msg_perr("EC response has invalid checksum\n");
  294. return -EC_RES_INVALID_CHECKSUM;
  295. }
  296. /* Return actual amount of data received */
  297. return rs.data_len;
  298. }
  299. static int read_memmap_lm4(uint16_t port, uint8_t * value)
  300. {
  301. *value = inb(port);
  302. return 0;
  303. }
  304. static int write_memmap_lm4(uint8_t value, uint16_t port)
  305. {
  306. outb(value, port);
  307. return 0;
  308. }
  309. /*
  310. **************************** EC API v2 ****************************
  311. */
  312. static int cros_ec_command_lpc_lm4(int command, int version,
  313. const void *outdata, int outsize,
  314. void *indata, int insize) {
  315. return cros_ec_command_lpc(command, version, outdata, outsize,
  316. indata, insize, read_memmap_lm4, write_memmap_lm4);
  317. }
  318. /*
  319. **************************** EC API v3 ****************************
  320. */
  321. static int cros_ec_command_lpc_v3_lm4(int command, int version,
  322. const void *outdata, int outsize,
  323. void *indata, int insize) {
  324. return cros_ec_command_lpc_v3(command, version, outdata, outsize,
  325. indata, insize, read_memmap_lm4, write_memmap_lm4);
  326. }
  327. static struct cros_ec_priv cros_ec_lpc_priv = {
  328. .detected = 0,
  329. .ec_command = cros_ec_command_lpc_lm4,
  330. };
  331. static struct opaque_programmer cros_ec = {
  332. .max_data_read = EC_HOST_CMD_REGION_SIZE,
  333. .max_data_write = 64,
  334. .probe = cros_ec_probe_size,
  335. .read = cros_ec_read,
  336. .write = cros_ec_write,
  337. .erase = cros_ec_block_erase,
  338. };
  339. /*
  340. * The algorithm is following:
  341. *
  342. * 1. If you detect EC command args support, success.
  343. * 2. If all ports read 0xff, fail.
  344. * 3. Try hello command (for API v0).
  345. *
  346. * TODO: This is an intrusive command for non-Google ECs. Needs a more proper
  347. * and more friendly way to detect.
  348. */
  349. static int detect_ec(struct cros_ec_priv *priv) {
  350. int i;
  351. int byte = 0xff;
  352. int old_timeout = ec_timeout_usec;
  353. #if USE_CROS_EC_LOCK == 1
  354. msg_gdbg("Acquiring CROS_EC lock (timeout=%d sec)...\n",
  355. CROS_EC_LOCK_TIMEOUT_SECS);
  356. if (acquire_cros_ec_lock(CROS_EC_LOCK_TIMEOUT_SECS) < 0) {
  357. msg_gerr("Could not acquire CROS_EC lock.\n");
  358. return 1;
  359. }
  360. #endif
  361. /*
  362. * Test if the I/O port has been configured for Chromium EC LPC
  363. * interface. If all the bytes are 0xff, very likely that Chromium EC
  364. * is not present.
  365. *
  366. * TODO: (crosbug.com/p/10963) Should only need to look at the command
  367. * byte, since we don't support ACPI burst mode and thus bit 4 should
  368. * be 0.
  369. */
  370. byte &= inb(EC_LPC_ADDR_HOST_CMD);
  371. byte &= inb(EC_LPC_ADDR_HOST_DATA);
  372. for (i = 0; i < EC_OLD_PARAM_SIZE && byte == 0xff; ++i)
  373. byte &= inb(EC_LPC_ADDR_OLD_PARAM + i);
  374. if (byte == 0xff) {
  375. msg_pdbg("Port 0x%x,0x%x,0x%x-0x%x are all 0xFF.\n",
  376. EC_LPC_ADDR_HOST_CMD, EC_LPC_ADDR_HOST_DATA,
  377. EC_LPC_ADDR_OLD_PARAM,
  378. EC_LPC_ADDR_OLD_PARAM + EC_OLD_PARAM_SIZE - 1);
  379. msg_pdbg(
  380. "Very likely this board doesn't have a Chromium EC.\n");
  381. return 1;
  382. }
  383. /*
  384. * Test if LPC command args are supported.
  385. *
  386. * The cheapest way to do this is by looking for the memory-mapped
  387. * flag. This is faster than sending a new-style 'hello' command and
  388. * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag
  389. * in args when it responds.
  390. */
  391. if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E' ||
  392. inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C') {
  393. msg_perr("Missing Chromium EC memory map.\n");
  394. return -1;
  395. }
  396. i = inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS);
  397. if (i & EC_HOST_CMD_FLAG_VERSION_3) {
  398. /* Protocol version 3 */
  399. priv->ec_command = cros_ec_command_lpc_v3_lm4;
  400. #if 0
  401. /* FIXME(dhendrix): Overflow errors occurred when using
  402. EC_LPC_HOST_PACKET_SIZE */
  403. cros_ec.max_data_write =
  404. EC_LPC_HOST_PACKET_SIZE - sizeof(struct ec_host_request);
  405. cros_ec.max_data_read =
  406. EC_LPC_HOST_PACKET_SIZE - sizeof(struct ec_host_response);
  407. #endif
  408. cros_ec.max_data_write = 128 - sizeof(struct ec_host_request);
  409. cros_ec.max_data_read = 128 - sizeof(struct ec_host_response);
  410. } else if (i & EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED) {
  411. /* Protocol version 2 */
  412. priv->ec_command = cros_ec_command_lpc_lm4;
  413. #if 0
  414. /*
  415. * FIXME(dhendrix): We should be able to use
  416. * EC_PROTO2_MAX_PARAM_SIZE, but that has not been thoroughly
  417. * tested so for now leave the sizes at default.
  418. */
  419. cros_ec.max_data_read = EC_PROTO2_MAX_PARAM_SIZE;
  420. cros_ec.max_data_write = EC_PROTO2_MAX_PARAM_SIZE;
  421. #endif
  422. } else {
  423. priv->ec_command = cros_ec_command_lpc_old;
  424. }
  425. /* Try hello command -- for EC only supports API v0
  426. * TODO: (crosbug.com/p/33102) Remove after MP.
  427. */
  428. /* reduce timeout period temporarily in case EC is not present */
  429. ec_timeout_usec = 25000;
  430. if (cros_ec_test(&cros_ec_lpc_priv))
  431. return 1;
  432. ec_timeout_usec = old_timeout;
  433. cros_ec_set_max_size(&cros_ec_lpc_priv, &cros_ec);
  434. return 0;
  435. }
  436. static int cros_ec_lpc_shutdown(void *data)
  437. {
  438. #if USE_CROS_EC_LOCK == 1
  439. release_cros_ec_lock();
  440. #endif
  441. return 0;
  442. }
  443. int cros_ec_probe_lpc(const char *name) {
  444. msg_pdbg("%s():%d ...\n", __func__, __LINE__);
  445. if (alias && alias->type != ALIAS_EC)
  446. return 1;
  447. if (cros_ec_parse_param(&cros_ec_lpc_priv))
  448. return 1;
  449. if (cros_ec_lpc_priv.dev && strcmp(cros_ec_lpc_priv.dev, "ec")) {
  450. msg_pdbg("cros_ec_lpc only supports \"ec\" type devices.\n");
  451. return 1;
  452. }
  453. if (detect_ec(&cros_ec_lpc_priv))
  454. return 1;
  455. msg_pdbg("CROS_EC detected on LPC bus\n");
  456. cros_ec_lpc_priv.detected = 1;
  457. cros_ec_priv = &cros_ec_lpc_priv;
  458. if (buses_supported & BUS_SPI) {
  459. msg_pdbg("%s():%d remove BUS_SPI from buses_supported.\n",
  460. __func__, __LINE__);
  461. buses_supported &= ~BUS_SPI;
  462. }
  463. register_opaque_programmer(&cros_ec);
  464. buses_supported |= BUS_LPC;
  465. if (register_shutdown(cros_ec_lpc_shutdown, NULL)) {
  466. msg_perr("Cannot register LPC shutdown function.\n");
  467. return 1;
  468. }
  469. return 0;
  470. }