XO 1.75 HOST to EC Protocol - Strawman
Proposed XO 1.75 HOST<->EC protocol
The following document is a draft and a work in progress.
Paul Fox and I spent sometime thinking about how the SPI protocol between HOST and EC should work. The following is what we came up with. We would like to circulate the ideas for wider review.
gnu - the Discussion page seems to document a completely different protocol - and to have no discussion about this one. What's the story?
Challenges
SPI interfaces are inherently synchronous yet HOST to EC communication is inherently asynchronous. With SPI when you transmit a byte you get a byte in response regardless if the other side actually had valid data in its transmit FIFO. In the KB3930 an attempt to read from the Tx FIFO when there is no data will result in a zero. Avoiding the transmission of bogus zeros during the exchange meant trying to force an async system to operate synchronously. This seem seemed to have many sources of races and in general be fragile. So instead we chose to add framing and escaping around the protocol data stream such that if a bogus zeros in the data stream does occur it will be ignored.
Packet, Framing & Escaping
Basic packet structure
An un- framed un-escaped data packet is structured like the following:
- <Cmd/Response> < Data > ..... < Data N>
- <Cmd/Response>
- In Host -> EC this is the command for the EC to execute.
- In EC -> Host this is the result of the command executed. Valid command numbers are 0x01 - 0x7f. Bit 7 is reserved for the response if there is error. The response value is the same as the command value only if the command did not complete or failed then bit 7 will be set. See the command section for a list of all command and descriptions
- Data bytes for the command. The value of N is inherent in each command. Each side should maintain a packet buffer that is large enough to hold the largest known command after the framing and escaping has been removed. The current max data payload is for cmd 0x17 CMD_READ_GAUGE_ID which returns 8 bytes.
Multi-byte numbers are big endian sent MSB first. ie 0x01020304 would be sent in the data stream as 0x01 0x02 0x03 0x04
All commands have a response packet. There are special conditions where a response packet will be sent without a corresponding command packet. This is for keyboard and for mouse data. These responses do not have a command.
Example
Command 0x85. Read wakeup source
Cmd: 0x43
Rsp: 0x43 0x02
Or if there was an error (ie there was not a wakeup available)
Cmd: 0x43
Rsp: 0xC3
Command 0x36. Set EC wakeup.
Cmd: 0x36 0x00 0x00 0x12 0x34
Rsp: 0x36
Command 0x44. Read EC location
Cmd: 0x44 0xFE 0xE0
Rsp: 0x44 0xAA
Framing & Escaping
The framing protocol reserves sixteen bytes for its own use. These bytes are considered special and must be escaped if they show up as packet data. The sixteen bytes are 0xF1 - 0xFF and 0x00. Not all sixteen bytes are currently defined.
Defined bytes are:
- 0xF1 Start of frame
- 0xF2 End of frame
- 0xF3 Escape byte
- 0x00 Ignored
- 0xF4 - 0xFF Reserved
If one of the above values occurs in the data stream then it must be escaped by 0xF3 and the value adjusted by 16. When transmitting 0x10 is subtracted from the value and when receiving 0x10 is added. When framed and escaped the above examples become:
Command 0x43. Read wakeup source
Host -> EC: 0xF1 0x43 0xF2
EC -> Host: 0xF1 0x43 0x02 0xF2
Same command but returning an error
Host -> EC: 0xF1 0x43 0xF2
EC -> Host: 0xF1 0xC3 0xF2
Command 0x36. Set EC wakeup.
Host -> EC: 0xF1 0x36 0xF3 0xF0 0xF3 0x00 0x12 0x34 0xF2
EC -> Host: 0xF1 0x36 0xF2
quozl - there are other byte escaping schemes that already exist; but whether you use them depends on what code you can use. i guess you might have some reason for choosing 0xF3. easier in hex dumps than 0x10 DLE? ;-)
gnu - you should only use one reserved byte for start/end of frame (e.g. 0xF1). That way you can do back to back packets with only a single framing byte between them, saving about 30% of your overhead when constrained by link speed. Back to back framing bytes (zero length frames) are ignored (and are normally transmitted unless an second frame is immediately ready). The PCnet protocols in about 1979 used this structure (@ was the framing char since it tended to re-sync asynchronous modems that had lost their start/stop bit sync; is there any chance of this happening in SPI?). Given the vagaries of SPI hardware, the protocol should probably ignore both 0x00 and 0xFF when they appear on the wire, not just 0x00. Will the framing layer know or be able to check frame lengths? Will you be able to send multiple bytes of e.g. touchpad or touchscreen data in a single frame?
Hardware Signals
Hardware Flow Control
The fifos in the kb3930 are 4 bytes deep. Therefore there must be some hardware flow control to prevent them from being overwritten by the host. The armada 610 provides a SSP0_SRDY signal which may be asserted to stop the transmission of data from the host. This signal is normally asserted. The kb3930 should de-assert this signal in response to an Rx FIFO full event. This signal will be re-asserted when the kb3930 has cleared the FIFO. This signal will also be de-asserted while the kb3930 is processing a command.
wmb - I don't see SSP0_SRDY in the Armada docs. I see SSP1_SRDY and SSP3_SRDY .
quozl - plan what to do when the host never sees this signal de-asserted? i presume it would mean a non-clocking EC.
EC request to send
In some circumstances the EC needs to send data to the host without a prior request. Examples are keyboard keypresses, mouse data and battery status changes. In these cases the EC will assert the EC_IRQ signal. The host should then query the EC. This signal will be de-asserted by the EC when all pending requests have been serviced.
Data Exchange Diagram
FIXME <some sort of diagram showing a data exchange with the flow control signals>
EC Code implementation
The EC code will consist of various parts.
Interrupt service routines
- Rx FIFO full
- The Rx full ISR should assert SSP0_SRDY
Data Stream Handler
The data stream handler is responsible for reading and writing the data stream to and from the hardware fifos. It handles removing or inserting the protocol framing and moving resulting data to and from the command and response buffers. It is also responsible for re-asserting the SSP0_SRDY signal if the Rx full ISR has de-asserted it.
- Inputs
- command in process flag
- bytes in Rx fifo
- bytes in Tx fifo
- Rx fifo data
- response buffer
- Outputs
- command in process flag
- command packet ready
- command buffer
- Tx fifo data
The following state logic psudocode summarizes the data stream handler
State_Idle if ( (Rx fifo > 0) && (!command in process) ) goto State_Rx_Data; if (response packet ready) goto State_Tx_Data; State_Rx_Data while (Rx fifo > 0) read data byte and deframe if (framing error) goto State_resync; insert data byte into command buffer if (end of frame) set command in process flag goto State_flowcontrol State_Tx_Data while ( (Tx fifo < 2) && (response packet ready) ) get data byte from response buffer frame data and push into Tx if (end of data) clear response packet ready goto State_Idle State_flowcontrol if ( (Rx fifo < 3) && (!SSP0_SRDY) ) disable Rx full ISR assert SSP0_SRDY enable Rx full ISR
gnu - if rx involves tx in hardware, you should service tx first, so that as rcvd stuff comes in, the tx bytes are real data rather than just filler bytes.
Cmd/Response Handler
The command response hander reads or writes the commands/responses into the appropriate buffers and executes the requested commands.
- Inputs
- Input from various EC subsystems
- command in process flag
- command buffer
- response data
- response needed flag
- Outputs
- command in process flag
- response buffer
- response packet ready
The following state logic psudocode summarizes the cmd/response handler
State_Idle if (command in process) goto State_do_command; response needed = check_ec_subsystems(); if ((response needed) && !(response packet ready) ) goto State_do_response; State_do_command read command process command and data if (immediate response) build response packet set response packet ready goto State_Idle State_Do_response get_ec_subsystem_data build response packet set response packet ready got0 State_idle
1.75 Command/Response List
TODO: Add descriptions CMD_GET_API_VERSION 0x08 CMD_READ_VOLTAGE 0x10 CMD_READ_CURRENT 0x11 CMD_READ_ACR 0x12 CMD_READ_BATT_TEMPERATURE 0x13 CMD_READ_AMBIENT_TEMPERATURE 0x14 ?? Maybe CMD_READ_BATTERY_STATUS 0x15 CMD_READ_SOC 0x16 CMD_READ_GAUGE_ID 0x17 CMD_READ_GAUGE_DATA 0x18 CMD_READ_BOARD_ID 0x19 CMD_READ_BATT_ERR_CODE 0x1f CMD_RESET_EC 0x28 CMD_READ_BATTERY_TYPE 0x2c CMD_SET_AUTOWAK 0x33 CMD_SET_EC_WAKEUP_TIMER 0x36 CMD_READ_EXT_SCI_MASK 0x37 CMD_WRITE_EXT_SCI_MASK 0x38 CMD_CLEAR_EC_WAKEUP_TIMER 0x39 CMD_ENABLE_RUNIN_DISCHARGE 0x3B CMD_DISABLE_RUNIN_DISCHARGE 0x3C CMD_READ_MPPT_ACTIVE 0x3d CMD_READ_MPPT_LIMIT 0x3e CMD_SET_MPPT_LIMIT 0x3f CMD_DISABLE_MPPT 0x40 CMD_ENABLE_MPPT 0x41 CMD_READ_VIN 0x42 CMD_EXT_SCI_QUERY 0x43 CMD_READ_LOCATION 0x44 CMD_WRITE_LOCATION 0x45 CMD_KEYBOARD_CMD 0x46 CMD_TOUCHPAD_CMD 0x47 RSP_KEYBOARD_DATA 0x48 RSP_TOUCHPAD_DATA 0x49 CMD_GET_FW_VER 0x4a CMD_POWER_CYCLE 0x4b CMD_POWER_OFF 0x4c CMD_RESET_EC_SOFT 0x4d CMD_READ_GUAGE_U16 0x4e