Revised EC Port 6C Command Protocol: Difference between revisions
RafaelOrtiz (talk | contribs) m (category) |
(Pretty-printed table of actions in 2 columns. Cleaned up a few bits of wording.) |
||
(2 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
This is a replacement for an '''EC''' command protocol that was giving us problems. |
This is a replacement for an '''EC''' command protocol that was giving us problems. |
||
see [[Ec_specification#Old_Port_6c_Command_Protocol]] |
|||
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: |
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: |
||
Line 9: | Line 11: | ||
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. |
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. |
||
The CPU may abandon an in-progress command ''at any time'' by writing a new command byte to port 6c. |
|||
It depends on these facts: |
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 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: |
The protocol is as follows: |
||
{| style="margin: 1em 1em 1em 0; background: #f9f9f9; border: 1px #aaa solid; border-collapse: collapse;" |
|||
! CPU Actions || EC Actions |
|||
Starting from a quiescent state, where IBF=0 and OBF=0: |
|||
|- |
|||
| 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. |
|||
| |
|||
'''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 |
|||
'''E1''': EC receives IBF interrupt, checks register 0xfe9e bit 6 and observes that it |
|||
to "new command" state. |
|||
was 1, hence a new command. (If the bit is 0, this is a data byte; proceed to step E8.) |
|||
|- |
|||
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 |
|||
'''E2:''' EC cancels any previous commands by setting its state variables |
|||
be done prior to clearing IBF in a later step. This step discards |
|||
to "new command" state. |
|||
any residue from incomplete earlier commands, and step E2 cancels |
|||
|- |
|||
any tendency for earlier command to continue generating data. |
|||
| || |
|||
'''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 |
|||
to reg 0xfe9e, decodes the command, and sets a state variable accordingly. |
|||
be done prior to clearing IBF in a later step. This step discards |
|||
any residue from incomplete earlier commands, and step E2 has canceled |
|||
E5a: If the next step of the command is to send data to the CPU and |
|||
any tendency for earlier command to continue generating data. |
|||
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. |
|||
'''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. |
|||
|- |
|||
there are more steps after that, EC enables the OBF interrupt, puts |
|||
| || |
|||
the first data byte in the data register, and returns from the |
|||
'''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, |
|||
receive the OBF interrupt as described in E7.) |
|||
puts the data byte in the data register, sets state to "idle", |
|||
and returns from the protocol handler. |
|||
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, |
|||
'''E5b:''' If the next step of the command is to send data to the CPU and |
|||
the EC will perform step E8.) |
|||
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 |
|||
disables OBF interrupt, sets state to idle, and returns from the |
|||
receive the OBF interrupt as described in E7.) |
|||
protocol handler. |
|||
|- |
|||
| || |
|||
C2: If the next stage of the command is an EC-to-CPU data byte, the CPU |
|||
'''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. |
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. |
IBF must be included in the test, since it makes the E3 interlock work. |
||
Line 67: | Line 81: | ||
drive OBF to 0 while IBF is still 1, so the IBF,OBF=0,1 test will not |
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. |
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 |
|||
'''E6:''' If that byte was the last thing in the command sequence, the EC |
|||
interrupt. The EC is already back in idle state, so it does not |
|||
will not receive an OBF interrupt because step E5a disabled the |
|||
need notification that the CPU read the byte. |
|||
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. |
|||
'''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 |
|||
C3: If the next stage of the command is a CPU-to-EC data byte, the CPU |
|||
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. |
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 |
'''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 |
|||
processing the command. |
|||
according to the command semantics, and goes to step E5 to continue |
|||
processing the command. |
|||
|} |
|||
Note that there is no need for arbitrary delays. |
Note that there is no need for arbitrary delays. |
||
Line 100: | Line 120: | ||
[[Category:developers]] |
[[Category:developers]] |
||
[[Category:Firmware]] |
[[Category:Firmware]] |
||
[[Category:EC]] |
Latest revision as of 08:13, 8 January 2011
This is a replacement for an EC command protocol that was giving us problems.
see Ec_specification#Old_Port_6c_Command_Protocol
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.
The CPU may abandon an in-progress command at any time by writing a new command byte to port 6c.
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:
CPU Actions | EC Actions |
---|---|
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. (If the bit is 0, this is a data byte; proceed to step E8.) | |
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 has canceled 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 semantics, 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.