Ec specification

From OLPC
Jump to navigation Jump to search
  This page is monitored by the OLPC team.

Operational Specification of the XO embedded controller (EC)

These pages will eventually document the commands and responsibilities of the EC in the XO system. Currently its not much more than a cut and paste from a variety of emails, trac tickets, and operational info extracted from the way the EC is known to work. Some of the descriptions are a bit odd and terse as the source is from non-native English speakers. More verbosity and better descriptions will be added as time allows.


EC New Port 6c Command List

These commands are issued using a complicated protocol - see #New Port 6c Command Protocol.

  • 0x10 Read voltage (2 bytes)
  • 0x11 Read current (2 bytes)
  • 0x12 Read ACR (2 bytes)
  • 0x13 Read battery temperature (2 bytes)
  • 0x14 Read ambient temperature (2 bytes)
  • 0x15 Read battery status (1 byte)
    • Bit 0: 1: battery exists
    • Bit 1: 1: battery full charged
    • Bit 2: 1: battery low
    • Bit 3: 1: battery destroyed
    • Bit 4: 1: AC in
    • Bits 5-7 Not defined
  • 0x16 Read Battery State of Charge (SOC) (1 byte)
  • 0x17 Read Battery gas gauge chip serial number (6 bytes)
  • 0x18 Read Battery gas gauge data
  • 0x19 Read board id (1 byte)
  • 0x1a Read SCI source (1 byte)
    • 0x01 Game button
    • 0x02 Battery Status Change. Generated for any of:
      • AC plugged/unplugged
      • Battery inserted/removed
      • Battery Low
      • Battery full
      • Battery destroyed
    • 0x04 Battery SOC Change
    • 0x08 Battery subsystem error
    • 0x10 Ebook mode change
    • 0x20?? Lid status change
  • 0x1b Write SCI mask (1 byte)
  • 0x1c Read SCI mask (1 byte)
  • 0x1d Game key status (2 bytes) 9 bits of key status. 1 indicates key is depressed.
    • Bit 1: KEY_LR_R
    • Bit 2: KEY_RT_R
    • Bit 3: KEY_UP_L
    • Bit 4: KEY_DN_L
    • Bit 5: KEY_LF_L
    • Bit 6: KEY_RT_L
    • Bit 7: KEY_COLOR/MONO
    • Bit 8: KEY_UP_R
    • Bit 9: KEY_DN_R
  • 0x1e Set date (day/mon/year)
    • Need details for using this.
  • 0x1f Read battery subsystem error code (1 byte)
    • 0x02 Pack info fail (LiFePO4 & NiMH)
    • 0x04 Over voltage checking fail (LiFePO4)
    • 0x05 Over temperature (58C) (LiFePO4)
    • 0x06 Gauge stop or sensor break (LiFePO4 & NiMH)
    • 0x07 Sensor out of control (NiMH)
    • 0x09 Battery ID fail & temperature > 52C
    • 0x10 ACR fail (NiMH)
  • 0x20 Init NiMH Battery
  • 0x21 Init LiFePO4 Battery
  • 0x23 Set WLAN Power on/off
  • 0x24 Wake up WLAN
  • 0x25 WLAN reset
  • 0x26 DCON power enable/disable
  • 0x27?? Read power rail status
    • DCON status
    • WLAN status

The following commands are an ill-considered alternative to #Indexed access to EC internal locations, and might be removed in the future.

  • 0x80 // read address from mailbox
  • 0x81 // write address to mailbox
  • 0x82 // read data(word) from mailbox
  • 0x83 // write data(word) to mailbox
  • 0x84 // read data(byte) from mailbox
  • 0x85 // write data(byte) to mailbox
  • 0x88 // read EC RAM(word)to mailbox data referring mailbox address
  • 0x89 // write mailbox data into EC RAM(word) referring mailbox address
  • 0x8A // read EC RAM(byte)to mailbox data referring mailbox address
  • 0x8B // write mailbox data into EC RAM(byte) referring mailbox address


EC Old Port 6c Command List

See #Old Port 6c Command Protocol.

  • 0x01 1.: Set MIC_AC to high (write 0x01 to port 6c, read 0 from port 68)
    This command is obsolete on B2 and later hardware, where MIC_AC is controlled by a 5536 GPIO
  • 0x02: Set MIC_AC to low (default) (write 0x01 to port 6c, read 0 from port 68)
    This command is obsolete on B2 and later hardware, where MIC_AC is controlled by a 5536 GPIO
  • 0x03: Active the SPI write protect (write 0x03 to port 6c, read 0 from port 68)
    SPIWP# signal is high, then DSPIWP# signal will be low.

    The DSPIWP# signal will be low forever until the ECRST# is asserted.
    The DSPIWP# signal will not be high even 0x04 command is issued again.
  • 0x04: Deactivate SPI write protect (write 0x04 to port 6c, read 0 from port 68)
    SPIWP# signal is low (default), and DSPIWP# signal will be high.
    Once the DSPIWP# is low, it will not be high even this command is issued again.
  • 0x05: Reset system (write 0x05 to port 6c, read 0 from port 68)
    This command forces a hard reset of the EC, so that it is possible to write to SPI flash after the system is turned on again.
  1. The SPI flash upgrade tool sends 0x05 command to the EC
  2. The EC asserts EC_WP#
  3. EC_WP# will trigger ECRST#
  4. The whole system is reset.
  5. User needs to press the power button to power on.
  • 0x06: Activate LED light (write 0x06 to port 6c, read 0 from port 68)
    Sets LED_light# signal to low
  • 0x07: Deactivate LED light (write 0x07 to port 6c, read 0 from port 68)
    LED_light# signal is high (default)
  • 0x08: Simple EC revision (write 0x08 to port 6c, read revision code from port 68)
  • 0x09: Get chip type (write 0x08 to port 6c, read chip type from port 68)
    • Type = 0x09 for 3920 (A-test boards only)
    • Type = 0x00 for 3700 (B-test and later boards)
  • 0x0A: Set SIRQ Quiet Mode (write 0x0a to port 6c, read 0 from port 68)
  • 0x0B: Set SIRQ Continuous Mode (write 0x0b to port 6c, read 0 from port 68)

New Port 6c Command Protocol

Here is how the EC Command Protocol works, assuming that you are polling the I/O ports (not using interrupts):

1. Read port 6c.

1a. If bit 7 = 1, it means that a previous use of the port failed to release it. Since the OLPC Open Firmware is single-threaded, there is no other possible "owner" of the port, so OFW can "take it back". Write 0xff to port 6c, delay 1 millisecond, and go back to step 1.

1b. At this point, bit 7 = 0 and the port is now "owned".

1c. If bit OBF = 1, it means that there is a byte in the output buffer, so read port 68 to consume that byte, delay 1 millisecond, reread port 6c, repeat step 1c. (This happens because when the previous "owner" released the port by writing 0xff to port 6c, it causes OBF to go to 1 after a few hundred microseconds.) (I have not seen any cases where it was necessary to consume more than one byte at this step.)

1d. At this point, bit 7 = 0 and OBF = 0, indicating that we have ownership and the data buffer is empty.

2. Poll port 6c until IBF = 0 or until a timeout occurs, delaying 4 millisecond between polls. If you do not delay between polls, timeouts occur frequently. If you omit this step entirely, step 5 often times out.

3. Send the command by writing the command number to port 6c.

4. Poll port 6c until IBF =0 or until a timeout occurs, delaying 4 milliseconds between polls. (This is David's step 3; after adding it, my code started working reliably).

5. Poll port 6c until OBF=1 or until a timeout occurs, delaying 1 millisecond between polls.

6. Read port 68 to consume the 0xff byte that the command puts in the output buffer (this is not the result value from the command itself; it is just a byte that seems to occur whenever you write anything to port 6c).

If you are expecting one or more bytes of return data from the command, you must do steps 7-10 for each such byte:

7. Poll port 6c until IBF =0 or until a timeout occurs, delaying 4 milliseconds between polls.

8. Write 0 to port 68. (Exception: for command 0x18 - Read battery gas gauge data - write 0x31 instead of 0.)

9. Poll port 6c until IBF=0 or until a timeout occurs, delaying 4 milliseconds between polls.

10. Poll port 6c until OBF=1 or until a timeout occurs, delaying 1 millisecond between polls.

11. Read the data from port 68.

If the command requires you to write argument values, you must do steps 7a-9a for each such byte.

7a. Poll port 6c until IBF =0 or until a timeout occurs, delaying 4 milliseconds between polls.

8a. Write data byte to port 68.

9a. Poll port 6c until IBF=0 or until a timeout occurs, delaying 4 milliseconds between polls.

When you are finished with the command:

12. Write 0xff to port 6c to release the port.

A few hundred microseconds after you perform step 11, the OBF bit will go to 1, indicating that a data byte was placed in the buffer. You cannot poll port 6c to determine when that byte is available for consumption, because that will re-acquire the ownership bit. That is why step 1b is necessary - you must consume that stray byte at the start of the next command sequence.

Old Port 6c Command Protocol

The Old Port 6c Command Protocol is subset of the New Port 6c Command Protocol You do not need steps 7 - 11. The value from port 68 is step 6 is 0 instead of 0xff, except for commands 0x08 and 0x09, where it is the result data.


EC IO Pinout

  • Pin 6: GPIO00 VR_ON#
  • Pin 9: GPIO01 WLAN_EN
  • Pin 10: GPIO02 SWI#
  • Pin 23: GPIO06 TX
  • Pin 24: GPIO07 RX/BAT_L0
  • Pin 25: GPIO08 EC_EAPD
  • Pin 26: GPIO09 LED_PWR#
  • Pin 27: GPIO0A LED_CHG_R#
  • Pin 28: GPIO0B WAKEUP
  • Pin 29: GPIO0C PWR_BUT#
  • Pin 31: GPIO0E CHG
  • Pin 32: GPIO0F CC0
  • Pin 37: GPIO10 EC->WLAN Wakeup
    • Fix schematic!!
  • Pin 1: GPIOE0 EC_WP#
  • Pin 2: GPIOE1 CV_SET
  • Pin 3: GPIOE2 DQ
  • Pin 4: GPIOE3 LED_CHG_G
  • Pin 33: GPIOE8 BAT_L1
  • Pin

Board ID Values

The EC is responsible for determining the motherboard ID of a laptop. At the circuit level, this is specified by the ratio of the values of two resistors (R535 and R534). Known combinations include:

VoltageEC ValueBoard IDComments
000-07hB3
08-17hguard band
1/8 * 3.3V18-27hB4
28-37hguard band
1/4 * 3.3V38-47hN
48-57hguard band
3/8 * 3.3V58-67hN + 1
68-77hguard band
1/2 * 3.3V78-87hB2
88-97hguard band
5/8 * 3.3V98-A7hN + 2
A8-B7hguard band
3/4 * 3.3VB8-C7hN + 3
C8-D7hguard band
7/8 * 3.3VD8-E7hN + 4
E8-F7hguard band
3.3VF8-FFhN + 5

KeyCodes for Buttons

Key matrix Make code Break code
Bit 9: KEY_DN_R, {0xE0,0x66,0x00} {0xE0,0xE6,0x00}
Bit 8: KEY_UP_R, {0xE0,0x65,0x00} {0xE0,0xE5,0x00}
Bit 7:KEY_COLOR/MONO {0x69,0x00,0x00} {0xE9,0x00,0x00}
Bit 6: KEY_RT_L, {0x68,0x00,0x00} {0xE8,0x00,0x00}
Bit 5: KEY_LF_L, {0x67,0x00,0x00} {0xE7,0x00,0x00}
Bit 4:KEY_DN_L, {0x66,0x00,0x00} {0xE6,0x00,0x00}
Bit 3: KEY_UP_L, {0x65,0x00,0x00} {0xE5,0x00,0x00}
Bit 2: KEY_RT_R, {0xE0,0x68,0x00} {0xE0,0xE8,0x00}
Bit 1:KEY_LR_R {0xE0,0x67,0x00} {0xE0,0xE7,0x00}

Firmware Address Map

0x00000 - 0ffff EC
0x10000 - dffff OFW
0xe0000 - ef7ff Reserved
0xef800 - effff Manufacturing data
0xf0000 - fffff Early startup code

Port 66 Commands

There are also some EC commands that use ports 0x66 and 0x62. Some of these are standard ACPI commands as defined in the external ACPI spec, others are custom.

The port 66 protocol is essentially the standard ACPI EC interface protocol.

1. Wait for port66.IBF = 0

2. Write command byte to port 66.

3. For each outgoing data or address byte:

3a. Wait for port66.IBF = 0

3b. Write data or address byte to port 62.

4. For each incoming data byte:

4a. Wait for port66.OBF = 1

4b. Read data byte from port 62.

5. If the command requires no data or address bytes, you can determine when the command was accepted/executed by waiting for port66.IBF=0.

ACPI-defined port 66 commands

  • 0x80 Read EC (write 0x80 to port 66, write address byte to port 62, read data byte from port 62)
  • 0x81 Write EC (write 0x81 to port 66, write address byte to port 62, write data byte to port 62)
  • 0x82 Burst Enable (write 0x82 to port 66, read data byte from port 62 - the data byte is "burst ACK", value 0x90)
  • 0x83 Burst Disable (write 0x83 to port 66, wait for port66.IBF=0)
  • 0x84 Query EC (i.e. read SCI event queue) (write 0x84 to port 66, read data byte from port 62). When the data byte is 0, it means that the SCI event queue is empty.

OLPC-specific port 66 commands

  • 0xd5 Power Off (write 0xd5 to port 66)
  • 0xd8 Keyboard stop (write 0xd8 to port 66) Useful when updating EC microcode in SPI FLASH
  • 0xdd Keyboard pause (write 0xdd to port 66) Useful when updating manufacturing data
  • 0xdf Keyboard resume (write 0xdf to port 66) Useful when updating manufacturing data

Indexed access to EC internal locations

You can access some internal locations inside the EC with an index/data protocol. The "address" is a 16-bit number.

Write address.hi_byte to port 0x381, write address.lo_byte to port 0x382, and read or write the data byte at port 0x383.

For successive accesses to the same or nearby addresses, you don't have to rewrite address bytes that don't change.

We will probably disable this feature in the future, since it is a security hole.