FEL/Protocol

=Overview= The FEL is actually a tiny usb stack implementing a special USB protocol.

Part of it is implemented in our tools repository and can be used as reference code.

Below is a specification for the protocol based on the official code. You can find it in uboot source: (usb_efex.h).

=Examples= Communication always performs according to following routine (→ send, ← receive, => expected length of message):

Example 1. FEL_VERIFY_DEVICE (get device info)

1. Send request → AWUSBRequest(cmd = AW_USB_WRITE, len = 16)  => len(sizeof(AWUSBRequest) => 32) → AWFELStandardRequest(FEL_VERIFY_DEVICE)     => len(sizeof(AWFELStandardRequest) => 16) ← AWUSBResponse(csw_status = 0)               => len(sizeof(AWUSBResponse) => 13)

2. Read response → AWUSBRequest(cmd = AW_USB_READ, len = 32)  => len(sizeof(AWUSBRequest) => 32) ← AWFELVerifyDeviceResponse                  => len(sizeof(AWFELVerifyDeviceResponse) => 32) ← AWUSBResponse(csw_status = 0)              => len(sizeof(AWUSBResponse) => 13)

3. Read status → AWUSBRequest(cmd = AW_USB_READ, len = 8)   => len(sizeof(AWUSBRequest) => 32) ← AWFELStatusResponse(mark=-1,state=0)       => len(sizeof(AWFELStatusResponse) => 8) ← AWUSBResponse(csw_status = 0)              => len(sizeof(AWUSBResponse) => 13)

Example 2. FEL_DOWNLOAD (write data to device memory)

1. Send request → AWUSBRequest(cmd = AW_USB_WRITE, len = 16)           => len(sizeof(AWUSBRequest) => 32) → AWFELStandardRequest(FEL_DOWNLOAD, address, length)  => len(sizeof(AWFELStandardRequest) => 16) ← AWUSBResponse(csw_status = 0)                        => len(sizeof(AWUSBResponse) => 13)

2. Send data → AWUSBRequest(cmd = AW_USB_WRITE, len = )  => len(sizeof(AWUSBRequest) => 32) ← data                                                 => len ← AWUSBResponse(csw_status = 0)                        => len(sizeof(AWUSBResponse) => 13)

3. Read status → AWUSBRequest(cmd = AW_USB_READ, len = 8)   => len(sizeof(AWUSBRequest) => 32) ← AWFELStatusResponse(mark=-1,state=0)       => len(sizeof(AWFELStatusResponse) => 8) ← AWUSBResponse(csw_status = 0)              => len(sizeof(AWUSBResponse) => 13)

=Definition of messages= Default value is left after '=>'

AWUSBRequest (size 32) string  magic(4)             => "AWUC" uint32le tag                 => 0 uint32le len                 => [size of data written in next transfer] uint16le reserved1,          => 0 uint8   reserved2,           => 0 uint8   cmd_len,             => 0xC uint8   cmd                  => [request type AW_USB_READ (0x11) or AW_USB_WRITE(0x12)] uint8   reserved3,           => 0 uint32le len2                => len [same value] array   reserved4(uint8, 10) => {0}

AWUSBResponse (size 13) string  magic(4)           => "AWUS" uint32le tag               => 0 uint32le residue           => 0 uint8   csw_status         => 0 (if != 0, then request failed)

AWFELStatusResponse (size 8) uint16le mark              => 0xFFFF uint16le tag               => 0 uint8   state              => 0 (if !=0, something wrong happened) array   reserved(uint8, 2) => {0}

AWFELStandardRequest (size 16) uint16le cmd                => [one of the request e.g. FEL_VERIFY_DEVICE] uint16le tag                => 0 array   reserved(uint8, 12) => {0}

AWFELMessage (size 16) uint16le cmd,               => [one of the request e.g. FEL_DOWNLOAD, FEL_UPLOAD, FEL_RUN] uint16le tag,               => 0 (unused?) uint32le address            => 0 uint32le len                => 0 (length of read/write, 0 for FEL_RUN) uint32le flags              => 0 (used in FES mode)

AWFELVerifyDeviceResponse (size 32) string  magic(8)           => "AWUSBFEX" uint32le board             => Allwinner A31s (0x161000) uint32le fw                => 1 uint16le mode              => AL_VERIFY_DEV_MODE_FEL (1) uint8   data_flag          => 0x44 uint8   data_length        => 0x8 uint32le data_start_address => 0x7E00 array   reserved(uint8, 8) => {0}

=Requests= Full list of FEL request: FEL_VERIFY_DEVICE                      = 0x1 (Read length 32 => AWFELVerifyDeviceResponse) FEL_SWITCH_ROLE                        = 0x2 FEL_IS_READY                           = 0x3 (Read length 8) FEL_GET_CMD_SET_VER                    = 0x4 FEL_DISCONNECT                         = 0x10 FEL_DOWNLOAD                           = 0x101 (Write data to the device) FEL_RUN                                = 0x102 (Execute code) FEL_UPLOAD                             = 0x103 (Read data from the device)

=Memory information= Some useful info about memory of device in FEL mode. Dumped from A31 firmware image.
 * 1) 0x2000 - 0x6000   : INIT_CODE (16384 bytes)
 * 2) 0x7010 - 0x7D00   : FEL_MEMORY (3312 bytes)
 * 3) => 0x7010 - 0x7210: SYS_PARA (512 bytes)
 * 4) => 0x7210 - 0x7220: SYS_PARA_LOG (16 bytes)
 * 5) => 0x7220 - 0x7D00: SYS_INIT_PROC (2784 bytes)
 * 6) 0x7D00 - 0x7E00   : ? (256 bytes)
 * 7) 0x7E00 - ?        : DATA_START_ADDRESS (obtained by FEL_VERIFY_DEVICE)
 * 8) 0x40000000        : DRAM_BASE
 * 9) 0x4A000000        : u-boot.fex
 * 10) 0x4D415244        : SYS_PARA_LOG (second instance?)

=Flashing= Before proper flash process begins, device must be turned into FES mode. Here's exactly way how it's achieved based on A31 device flash USB communication


 * 1) FEL_VERIFY_DEVICE => mode: AL_VERIFY_DEV_MODE_FEL, data_start_address: 0x7E00
 * 2) FEL_VERIFY_DEVICE (not sure why it's spamming with this again)
 * 3) FEL_UPLOAD: Get 256 bytes of data (filled 0xCC) from 0x7E00 (data_start_address)
 * 4) FEL_VERIFY_DEVICE
 * 5) FEL_DOWNLOAD: Send 256 bytes of data (0x00000000, rest 0xCC) at 0x7E00 (data_start_address)
 * 6) FEL_VERIFY_DEVICE
 * 7) FEL_DOWNLOAD: Send 16 bytes of data (filled 0x00) at 0x7210 (SYS_PARA_LOG)
 * 8) FEL_DOWNLOAD: Send 6496 bytes of data (fes1.fex) at 0x2000 (INIT_CODE)
 * 9) FEL_RUN: Run code at 0x2000 (fes1.fex). DRAM is initialized. You can manipulate memory on DRAM_BASE address
 * 10) FEL_UPLOAD: Get 136 bytes of data (DRAM) from 0x7210 (SYS_PARA_LOG). Its DRAM data in same form as in dram_para section in script
 * 11) FEL_DOWNLOAD(12 times because u-boot.fex is 0xBC000 bytes): Send (u-boot.fex) 0x4A000000 in 65536 bytes chunks (last chunk is 49152 bytes and ideally starts at config.fex (also known as: script.bin) data)
 * 12) FEL_DOWNLOAD: Send 1 byte of data (0x10) at 0x0E offset of u-boot (0x4A00000E). This change uboot_spare_head.boot_data.work_mode to WORK_MODE_USB_PRODUCT (more (cmd_irq.c) . Important: if you skip this step device will boot normally
 * 13) FEL_RUN: Run code at 0x4A000000 (u-boot.fex). Pause: LiveSuit asks user if he would like to do format or upgrade
 * 14) FEL_VERIFY_DEVICE => mode: AL_VERIFY_DEV_MODE_SRV,  you can send FES commands now and you cannot send FEL commands anymore except FEL_VERIFY_DEVICE

Every LiveSuit image contains a compiled LUA plugin (aultools.fex) with a script. The script is loaded by LiveSuit and executed when flash process starts.

Check also legacy informations: USB-protocol.txt.