XO 1.75 HOST to EC Protocol - Strawman

From OLPC
Jump to navigation Jump to search

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