AP / EC communication

NOTE: This page needs a lot of work.



How does the application processor (AP) talk to the embedded controller (EC)?


  • buses: I2C, SPI, LPC
  • shared memory
  • userspace vs kernel
  • keyboard protocol

Host Command protocol and versions

Most of the messages passed between the AP and EC use the "host command" structures. As the software evolved, so did the commands.

As of 3/18/14:

There are three "version" concepts, all in include/ec_commands.h

First, there's the MKBP mess.

    #define EC_PROTO_VERSION          0x00000002
    #define EC_CMD_PROTO_VERSION 0x00

  This is useless. See crosbug.com/p/11223. On ARM systems using MKBP, the
  kernel sends EC_CMD_PROTO_VERSION and requires "2" for the result. Anything
  else just falls over.

Second, there's the way in which command/response packets are formatted and
sent from the AP to the EC and back.

  There are two protocol versions: 2 and 3 (1 never shipped). Version 3 is
  the current one, using

    #define EC_COMMAND_PROTOCOL_3 0xda
    #define EC_HOST_REQUEST_VERSION 3
    #define EC_HOST_RESPONSE_VERSION 3
    struct ec_host_request;
    struct ec_host_response;

  Version 2 is the previous one, just sending a few unstructured bytes
  before and after the packed request/response structs. Look for

    #define EC_PROTO2_*

  This command asks the EC "how do we send data to you?"

    #define EC_CMD_GET_PROTOCOL_INFO 0x0b

  It returns the protocol versions that the EC supports, as a bitmask (some
  ECs can speak both protocol 2 and protocol 3, due to scheduling fail).
  However, this command is only implemented on ECs that speak protocol
  version 3 and newer.

Third, there's the version of request/response structs that each distinct
command can support.

  For example, EC_CMD_FLASH_WRITE has both version 0 (fixed 64-bytes at a
  time) and version 1 (variable size).

    #define EC_CMD_GET_CMD_VERSIONS 0x08

  This command takes an EC command number and returns its supported versions
  as a bitmask - look for instances of EC_VER_MASK().

  But, EC_CMD_GET_CMD_VERSIONS only supports 8-bit cmds in its request
  struct, even with protocol version 3 which can send 16-bit commands .
  Randall is going to add a version 1 struct to that RSN. Until then,
  16-bit commands (if any) are limited to their own version 0.

So the process is as follows:

  First, the AP sends EC_CMD_GET_PROTOCOL_INFO. If the EC likes it, then it
  speaks at least proto 3 (and will indicate so in the returned bitmask).

  If the AP rejects that command, the AP sends EC_CMD_HELLO, packed in
  protocol version 2. If the EC likes that, the EC speaks protocol version 2
  so we can only send it 8-bit commands. If the EC doesn't like that,
  something's wrong.


BTW, the "SPIv3 bug" (crosbug.com/p/20820) refers only to the kernel-driver
support for talking to the EC using protocol version 3. U-Boot and
Depthcharge (and the EC) all support version 3. It's just the kernel that
doesn't how to use it.

Note: kernel v3.14 and 3.18 and later DO know how to speak proto v3. Everything in ToT from here on should use v3 or later, which use struct ec_host_request and struct ec_host_response.
In the kernel driver, the proto v3 comments and functions talk about sending "packets". Proto v2 uses "command". 

EC SPI protocol

The SPI bus is similar to I2C, but with two major exceptions. First, there's a minimum speed on the SPI bus. If slave devices don't respond quickly enough, the master will assume they're broken and give up. Second, every transaction is bidirectional. When bits are being clocked from master to slave on the MOSI line, the master will simultaneously read bits in the other direction on the MISO line.

Hardware devices can usually handle this, and often some hardware-based flow control used to "stretch" the transaction by a bit or byte if the slave device needs a little extra time to respond to the master's demands.

When exchanging messages with the EC on the SPI bus, the EC's host commands are communicated using our own software flow-control scheme, because most of the embedded controllers either aren't fast enough or don't have any support for hardware flow-control.

It works like this: When the AP sends a byte to the EC, if the EC doesn't have a response queued up in advance, a default "dummy" byte is returned. The EC preconfigures that default response byte to indicate its status (ready, busy, waiting for more input, etc). Once the AP has sent a complete command message, it continues clocking bytes to the EC (which the EC ignores) and just looks at the response byte that comes back. Once the EC has parsed the AP's command and is ready to reply, it sends a "start of frame" byte, followed by the actual response. The AP continues to read and ignore bytes from the EC until it sees the start of frame byte, and then it knows that the EC's response is starting with the next byte.

Look in include/ec_commands.h for these definitions:

EC_SPI_FRAME_START
EC_SPI_PAST_END
EC_SPI_RX_READY
EC_SPI_RECEIVING
EC_SPI_PROCESSING
EC_SPI_RX_BAD_DATA
EC_SPI_NOT_READY


Comments