Revised EC Port 6C Command Protocol

From OLPC
Revision as of 01:36, 18 May 2007 by Quozl (talk | contribs) (added symbol names and 0x in some places)
Jump to navigation Jump to search

This is a replacement for an EC command protocol that was giving us problems.

The objective is to transmit information back and forth between the CPU and the embedded controller (EC), via CPU I/O ports 0x68 and 0x6c. This protocol can support:

  • Commands with no data transfer
  • Commands that return data from the EC to the CPU
  • Commands that send data from the CPU to the EC
  • Commands that send data in both directions

This protocol is intended to be reliable, predictable, and efficient. Every step is interlocked in a coherent fashion, with no arbitrary delays or unnecessary steps and no unnecessary EC interrupts.

It depends on these facts:

  • The EC can receive an interrupt when the CPU writes a byte to either port 0x68 or port 0x6c when IBF=0, i.e. on a 0->1 IBF transition. To enable that interrupt, bit 1 of EC register 0xfe9d LPC68CFG must be set.
  • The EC can receive an interrupt when the CPU read a byte from port 0x68 when OBF=1, i.e. on a 1->0 OBF transition. To enable that interrupt, bit 0 of EC register 0xfe9d LPC68CFG must be set. (The protocol enables the OBF interrupt only as needed, during intermediate stages of multi-byte commands.)
  • The EC can distinguish between a write to port 0x68 and a write to port 0x6c, via bit 6 of EC register 0xfe9e LPC68CSR.

The protocol is as follows:

Starting from a quiescent state, where IBF=0 and OBF=0:

 - The EC idle state is "IBF interrupt enabled, OBF interrupt disabled, IBF=0, OBF=0"

C1: CPU waits until IBF=0, then sends the command by writing it to port 0x6c.

 E1: EC receives IBF interrupt, checks register 0xfe9e bit 6 and observes that it
 was 1, hence a new command.
 E2: EC cancels any previous commands by setting its state variables
 to "new command" state.
 E3: If OBF=1, EC clears it by writing 0x01 to reg 0xfe9e.  This is the
 crucial interlock that makes the protocol predictable - this must
 be done prior to clearing IBF in a later step.  This step discards
 any residue from incomplete earlier commands, and step E2 cancels
 any tendency for earlier command to continue generating data.
 E4: EC reads the command byte from reg 0xfe9f, clears IBF by writing 2
 to reg 0xfe9e,  decodes the command, and sets a state variable accordingly.
 E5a: If the next step of the command is to send data to the CPU and
 there are no more steps after that, EC disables the OBF interrupt,
 puts the data byte in the data register, sets state to "idle",
 and returns from the protocol handler.
 E5b: If the next step of the command is to send data to the CPU and
 there are more steps after that, EC enables the OBF interrupt, puts
 the first data byte in the data register, and returns from the
 protocol handler.  (When the CPU later reads the byte, the EC will
 receive the OBF interrupt as described in E7.)
 E5c: If the next step of the command is to receive data from the
 CPU, EC disables the OBF interrupt, and returns from the protocol
 handler. (When the CPU later writes the byte to the data register,
 the EC will perform step E8.)
 
 E5d: If there is no more data to be sent or received, the EC
 disables OBF interrupt, sets state to idle, and returns from the
 protocol handler.

C2: If the next stage of the command is an EC-to-CPU data byte, the CPU polls port 0x6c until IBF,OBF=0,1, then reads the data byte from port 0x68. IBF must be included in the test, since it makes the E3 interlock work. If there is leftover data that causes OBF to start out as 1, step E3 will drive OBF to 0 while IBF is still 1, so the IBF,OBF=0,1 test will not succeed until the EC reaches step E5a or E5b.

 E6: If that byte was the last thing in the command sequence, the EC
 will not receive an OBF interrupt because step E5a disabled the
 interrupt.  The EC is already back in idle state, so it does not
 need notification that the CPU read the byte.
 E7: If there are more bytes after this to send or receive, the EC
 will receive an OBF interrupt (because of step E5b) and go to step
 E5 to continue processing the command.

C3: If the next stage of the command is a CPU-to-EC data byte, the CPU polls port 6c until IBF=0, then writes the data byte to port 0x68.

 E8: When the CPU writes the byte to the data register, the EC will
 receive the IBF interrupt and notice (via reg 0xfe9e bit 6 = 0) that
 the write was to the data register.  The EC then reads the byte from
 reg 0xfe9f, clears IBF by writing 2 to reg 0xfe9e, handles the byte
 according to the command sematics, and goes to step E5 to continue
 processing the command.

Note that there is no need for arbitrary delays.

Note: The above description of the EC behavior assumes that, if another IBF or OBF interrupt occurs while the EC is processing the steps E1..E8, the handling of that interrupt will be deferred until the end of step E5x where it "returns from the protocol handler". The new interrupt will neither cause premature re-entry to the protocol handler code (E1..E8), nor be lost. If that is not the case, some additional complexity may be necessary.