view doc/FTDI-EEPROM-format @ 81:8b0a01b19fb9

doc/FTDI-EEPROM-format: update for the discovery of FTDI chips enforcing the requirement of using upper addresses for strings
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 26 Sep 2023 21:56:26 +0000
parents f14d04e4d85d
children
line wrap: on
line source

FTDI configuration EEPROM format
================================

Unfortunately FTDI never documented the format of their EEPROM configuration
structure - apparently they consider it a proprietary trade secret just like
the wire protocol spoken over USB between their chips and their closed-source
proprietary drivers.  All FOSS community support for these chips is based on
reverse engineering, and that includes the EEPROM format.

We (FreeCalypso) have not done any significant FTDI RE of our own - instead we
are taking the knowledge that already exists in the FOSS community (including
RE-based knowledge of FTDI EEPROM format) and using it to produce better tools.

The present document summarizes the bits of knowledge we have collected
regarding FTDI's EEPROM configuration structure - this knowledge base is what
our generator and decoder tools are built on, as well as shipped EEPROM
programming in all physical hw products made by FreeCalypso.

Word-based vs byte-based views
==============================

Before FTDI started integrating the EEPROM inside their FT232R and FT-X chips,
their original design used external serial EEPROMs of 93C46, 93C56 or 93C66
type.  These EEPROMs are physically structured as an array of 16-bit words - or
more precisely, some EEPROM parts support both word and byte organization modes,
selected by pin strapping, but FTDI chips require word-structured EEPROMs.

Given this physical organization, we tend to view the EEPROM structure as an
array of 16-bit words.  For some parts of the configuration structure, such as
16-bit ID words and UCS-2 strings, this word-based view is ideal - however,
there are also times when the EEPROM structure needs to be viewed in terms of
bytes:

* Some configuration parameters are given as bytes rather than words;

* Pointers from the fixed structure at the beginning of the EEPROM to string
  descriptors in the "user" area use byte-based addressing.

The correspondence order between bytes and words is little-endian.

Fixed header structure
======================

The first 10 words (20 or 0x14 bytes) of the EEPROM follow the same basic
structure across all known-to-us FTDI chips:

Word 0 (bytes 0x00 and 0x01): this word is best viewed as two separate bytes,
and these bytes encode FTDI-specific functions detailed later in this document.

Word 1 (bytes 0x02 and 0x03): USB vendor ID, called idVendor in the USB spec.

Word 2 (bytes 0x04 and 0x05): USB product ID, called idProduct in the USB spec.

Word 3 (bytes 0x06 and 0x07): originally allocated for the bcdDevice word in
the USB device descriptor, see Table 9-8 in the USB 2.0 specification.  On older
FTDI chips such as FT2232D, the chip takes the value programmed in this EEPROM
word and actually reports this value in its device descriptor - thus if the
EEPROM is misprogrammed, all standard host software will be misled; see our
FTDI-chip-ID article.  OTOH, FT232R ignores this word and always reports its
bcdDevice as 0x0600; in terms of FT232R EEPROM images captured in the wild,
some have zero in this word while others have 0x0600.  FT2232H behaves like
FT232R (ignores this EEPROM word), but I haven't seen any EEPROM images with
this word zeroed out - it appears that FTDI's official tools still insert the
correct bcdDevice value.

Word 4 (bytes 0x08 and 0x09): this word is best viewed as two separate bytes.
Both bytes go into the USB configuration descriptor: byte 0x08 is bmAttributes
and byte 0x09 is bMaxPower.  See USB 2.0 specification Table 9-10 for the
detailed format.

Word 5 (bytes 0x0A and 0x0B): this word is best viewed as two separate bytes,
and these bytes encode FTDI-specific functions detailed later in this document.

Word 6 (bytes 0x0C and 0x0D): originally allocated for the bcdUSB word in the
USB device descriptor, indicating the version of the USB spec which the device
claims to support.  Starting with FT2232H this word has been repurposed for
other functions, as detailed in the chip-specific sections below.

Word 7 (bytes 0x0E and 0x0F): pointer to the manufacturer ID string; format
explained later in the string descriptors section.

Word 8 (bytes 0x10 and 0x11): pointer to the product ID string.

Word 9 (bytes 0x12 and 0x13): pointer to the serial number string if one is
present, otherwise 0.

FTDI-specific bytes in the fixed header
=======================================

Bytes 00, 01, 0A and 0B in the structure covered above are FTDI-specific (don't
correspond to any fields in any of the standard USB descriptors), and many of
the functions controlled by these bytes differ significantly from one FTDI chip
type to the next.

FT2232x bytes 00 and 01
-----------------------

On FT2232x chips bytes 00 and 01 configure channels A and B, respectively.
The 3 least significant bits of each byte encode the channel mode as follows:

0 = UART
1 = 245-style FIFO
2 = fast opto-isolated serial
4 = CPU-style FIFO

Bit 3 (mask 0x08) appears to have no function in the chip itself, but is used
by FTDI's Losedows drivers: for each of the two channels, FTDI's VCP driver is
selected if the bit is set and D2XX driver is selected if the bit is cleared.

On FT2232C/D only (not on FT2232H), bit 4 (mask 0x10) enables high current drive
on the respective A/B channel.

On FT2232H only, byte 01 bit 7 (mask 0x80) turns on a feature that is misnamed
"Suspend on DBus 7 Low" in FTDI's official programming tool.  It is misnamed
because the actual pin in question is BCBUS7, not "DBUS7".  When this function
is enabled via this bit, BCBUS7 becomes PWRSAV# input, which is sufficiently
documented in the FT2232H datasheet.

ftee-gen2232c and ftee-gen2232h default for both bytes is 0x08.

FT232R byte 00
--------------

This byte is conceptually similar to its counterpart on FT2232x, but not exactly
the same, and NOT compatible.  FT232R byte 00 bit assignments are as follows:

bit 0: 0 for FT232R, 1 for FT245R
bit 1: use external oscillator if set
bit 2: high current drive if set
bit 3: same VCP/D2XX nonsense as on other chips, but with reversed sense:
       0 means VCP, 1 means D2XX on this chip

ftee-gen232r default for this byte is 0x00.

FT232R byte 01
--------------

This byte is unique to FT232R: it sets the maximum packet size the chip
advertises for its Data In endpoint, via wMaxPacketSize in the endpoint
descriptor.  The standard value is 64 (0x40), and there does not seem to be
any need to change it.

Byte 0A on all FTDI chips
-------------------------

This byte has the same bit assignments across all FTDI chips we work with,
although newer chips don't support some of the older bits:

bit 0: isochronous endpoint control on FT232BM and FT2232C/D
bit 1: isochronous endpoint control on FT232BM and FT2232C/D
bit 2: enable suspend mode pull-down on I/O pins (all chips)
bit 3: 1 means serial number string present, 0 means serial # string absent
bit 4: set bcdUSB in device descriptor to EEPROM value (only up to FT2232C/D)
bit 5: isochronous endpoint control on FT2232C/D
bit 6: isochronous endpoint control on FT2232C/D

See chip-specific sections below for the details on isochronous endpoint
control bits.

ftee-gen* default for this byte is 0x00.

Byte 0B: FT2232x
----------------

This byte appears to be unused on FT2232C/D and on FT2232H.

Byte 0B: FT232R
---------------

This byte controls UART signal inversion.  Bits 0 through 7 (lsb through msb)
correspond to DBUS0 through DBUS7: if a given bit is set, the corresponding
DBUS/UART signal is inverted.

FT232BM specifics
=================

We don't have much support for this chip as it predates FreeCalypso involvement
in the business of FTDI chip tinkering - however, we know the following bits:

* The fixed part of the EEPROM config structure is just the 10 words described
  above, and the strings area begins at byte offset 0x14.

* Isochronous endpoint control via byte 0A appears to be the same as for
  Channel A of FT2232C/D, described below.

FT2232C/D specifics
===================

Words 0 through 9 (bytes up to 0x13) are as explained above.  The only
additional FT2232C/D-specific word is 10:

Byte 0x14 (low half of word 10) holds the EEPROM type: set to 0x46 for 93C46,
0x56 for 93C56 or 0x66 for 93C66.  It is not clear if the chip actually uses
this byte for anything: it seems to me that FTDI's EEPROM read engine has to
determine the required number of address bits (presumably by asking to read
address 0 and looking for the position of the dummy 0 bit from the EEPROM)
before it can proceed with incrementing addresses.  (The address bit order
in the serial EEPROM interface is big-endian, hence one needs to know the
correct number of address bits in order to increment linearly.)

Byte 0x15 (high half of word 10) appears to be unused.

The strings area of the EEPROM begins with word 11 or byte offset 0x16.

Isochronous endpoint control
----------------------------

The 4 data endpoints on this chip (In and Out for each channel) are of type
Bulk by default, but each of these 4 endpoints is independently selectable
between bulk and isochronous via these 4 bits in byte 0A:

bit 0: make Channel A data In endpoint isochronous
bit 1: make Channel A data Out endpoint isochronous
bit 5: make Channel B data In endpoint isochronous
bit 6: make Channel B data Out endpoint isochronous

FT2232H specifics
=================

On both FT2232H and FT4232H (which we don't support yet) EEPROM word 6
(originally allocated for bcdUSB override) is repurposed for I/O electrical
interface configuration.  The 16-bit word is divided into four 4-bit groups,
mapped to pins as follows:

Group #		FT2232H pins	FT4232H pins
--------------------------------------------
0		ADBUSx		ADBUSx
1		ACBUSx		BDBUSx
2		BDBUSx		CDBUSx
3		BCBUSx		DDBUSx

Within each group the 4 bits are assigned as follows:

Bits	Function
----------------
1:0	drive strength:
	00 = 4 mA
	01 = 8 mA
	10 = 12 mA
	11 = 16 mA
2	set to 1 for slow slew rate
3	set to 1 for Schmitt trigger

Other EEPROM quirks on FT2232H:

* Words 10 and 11, used on FT232R (chronologically between FT2232C and FT2232H)
  for CBUS configuration, appear to be reserved and unused on FT2232H.

* Word 12 on FT2232H is same as word 10 on FT2232C/D: EEPROM type code, even
  though it still isn't clear what the chip does with it, if anything.

* The strings area of the EEPROM begins with word 13 or byte offset 0x1A.

FT232R specifics
================

Words 0 through 9 (bytes up to 0x13) are as explained above.  The following
words 10 and 11 are specific to FT232R - they encode configured functions for
CBUSx pins as follows:

word 10 bits 3:0	CBUS0 config
word 10 bits 7:4	CBUS1 config
word 10 bits 11:8	CBUS2 config
word 10 bits 15:12	CBUS3 config
word 11 bits 3:0	CBUS4 config
word 11 bits 15:4	reserved

Please refer to libftdi source for the codes that go into individual 4-bit
fields for each CBUSx.

The strings area of the EEPROM begins with word 12 or byte offset 0x18.

USB string descriptors
======================

The standard USB device descriptor returned by FTDI chips has iManufacturer set
to 1 and iProduct set to 2, indicating presence of string descriptors at these
indices.  If byte 0A bit 3 is set, iSerialNumber is set to 3, otherwise
iSerialNumber is set to 0, indicating absence of serial number string.

The string descriptors themselves, returned upon the host asking for them at
these indices, are stored verbatim in the strings area of the EEPROM, i.e., in
the free space following the fixed configuration structure for each chip.

As defined in the USB spec, each string descriptor has the following structure:

1 byte:		total number of bytes in the descriptor
1 byte:		constant 0x03, meaning string descriptor
variable bytes:	string body in UCS-2

The total number of bytes in a string descriptor is the number of UCS-2
characters times 2 plus 2; this number is written into the first byte of the
descriptor itself, in the least-significant half of the first 16-bit word.  The
whole descriptor, consisting of this header word followed by UCS-2 character
words, can be placed at any EEPROM location within the "acceptable" area (see
below), and there is a pointer to each of the 3 possible string descriptors
from the fixed header structure at the beginning of the EEPROM.

Each of the 3 string pointers is one 16-bit word, structured as follows:

lower byte:	EEPROM byte address where the descriptor starts
		(see below regarding the most significant bit of this byte)
upper byte:	total number of bytes in the descriptor, same as written
		in the descriptor itself

String placement quirk
----------------------

Common sense says that the most natural way to pack the needed strings into the
EEPROM is to put the manufacturer ID string right after the fixed config
structure, then the product ID string and then the serial number string, if
included.  However, the EEPROM structure generated by FTDI's official tools is
slightly different:

* In the case of 93C56 or 93C66 EEPROMs, FTDI's official tools skip 64 words
  (128 bytes) after the end of the chip-defined config structure and then place
  the manufacturer ID string after this gap.  The byte-address pointer to each
  string descriptor always has its high bit set as a result of this quirk.

* In the case of 1024-bit EEPROMs (93C46 or FT232R internal) nothing is skipped,
  but the byte-address pointers to strings are written with the high bit set,
  as if the EEPROM were of 93C56 type.

My (Mother Mychaela's) first guess was that these quirks were just a matter of
FTDI's official tools being silly, and that those of us who write our own FOSS
tools can put our strings anywhere in the EEPROM, as long as the location we
pick doesn't conflict with something else.  However, experiments with real
boards featuring an FT2232x chip and an EEPROM reveal that the chip is NOT happy
when the most significant bit of the byte-address pointer to a string descriptor
is cleared: it appears that the chip is returning some kind of garbage to the
USB host when asked for the string descriptor in this case.  (I am using the
vague language of "appears that" because I am not currently able to allocate
the time to study the problem properly.)  Thus it appears that all strings MUST
be located in the upper half of 93C56, and the quirk of setting the msb of byte
address for 93C46 is also required.

Our ftee-gen* tools replicate both of these quirks, thus the resulting EEPROM
structure is the same as what the chip vendor's official tools produce.

ftee-gen* tools: config file language
=====================================

The format of EEPROM config files read by our ftee-gen* tools is line-based.
Each non-blank, non-comment line defines or tweaks one setting.  The following
settings are common to all ftee-gen* chip variants:

Setting		Format	Meaning
-------------------------------
ftdi-chip	keyword	Type of FTDI chip this config source was written for
eeprom		keyword	EEPROM size selector (not in ftee-gen232r)
vid		hex	USB vendor ID
pid		hex	USB product ID
manuf		string	Manufacturer ID string
product		string	Product ID string
byte00		hex	Raw setting of byte 00
byte01		hex	Raw setting of byte 01
byte08		hex	Raw setting of byte 08
byte0A		hex	Raw setting of byte 0A
maxpower	decimal	bMaxPower declaration, number in mA
usbver		hex	bcdUSB word (ftee-gen2232c and ftee-gen232r only)

Additional settings for FT2232H (ftee-gen2232h):

group0		hex	I/O electrical config for ADBUSx
group1		hex	I/O electrical config for ACBUSx
group2		hex	I/O electrical config for BDBUSx
group3		hex	I/O electrical config for BCBUSx

Additional settings for FT232R (ftee-gen232r):

byte0B		hex	Raw setting of byte 0B
cbus0		hex	CBUS0 config code
cbus1		hex	CBUS1 config code
cbus2		hex	CBUS2 config code
cbus3		hex	CBUS3 config code
cbus4		hex	CBUS4 config code

Only two settings are strictly mandatory: manuf and product strings.  For all
other settings the EEPROM generator tool provides chip-matching defaults:

* ftee-gen2232[ch] defaults match the configuration attained by the chip
  with a blank or missing EEPROM;

* ftee-gen232r defaults match FTDI's default factory programming of the
  chip-internal EEPROM.

As one can see, the config language is very low-level, most bits are set in raw
hex.  This design is justified by the paradigm of writing each config file once:
if you are designing a new board with an FTDI chip on it, and you need to change
some setting away from the FTDI chip's default, you research it once, figure out
the right bits, code the needed byte-level configuration in an EEPROM config
file, and then you just run a standard command line every time you need to
program a board.

The serial number string is never specified in the config file, instead it is
specified on the command line - this tool design is in accord with factory
production paradigm, where each EEPROM config is written once for a given board
design, and then a shell pipeline is executed for each board to be programmed.

Byte 0A bit 3 is always overridden by the generator tool based on the serial
number command line argument: set if a serial number is given and cleared if
this argument is omitted.

FTDI chip type matching
-----------------------

The design of FreeCalypso FTDI EEPROM tools calls for mostly manual matching
between EEPROM config files and generator tools: the operator is responsible
for selecting the correct tool (ftee-gen2232c, ftee-gen2232h or ftee-gen232r)
for the actual FTDI chip on the board of interest, and also responsible for
feeding correct EEPROM config files to this tool.  However, now that we are
starting to give EEPROM programming instructions to end users in the form of
"please run this shell pipeline", there is a natural desire to reduce potential
for operator error: if someone takes an EEPROM config file written for one FTDI
chip and feeds it to an ftee-gen* tool for a different chip, it would be nice
for this invalid combination to be detected and rejected.

Toward this end, the following optional settings may be included in EEPROM
config source files:

ftdi-chip FT2232C	# config valid only for ftee-gen2232c
ftdi-chip FT2232D	# same as FT2232C
ftdi-chip FT2232H	# config valid only for ftee-gen2232h
ftdi-chip FT2232x	# config valid for ftee-gen2232c and ftee-gen2232h
ftdi-chip FT232R	# config valid only for ftee-gen232r

EEPROM size selection
---------------------

In the case of EEPROM generator tools for FTDI chips with external EEPROMs,
one of the following settings may be included in the config source:

eeprom 93C46
eeprom 93C56
eeprom 93C66

If one of these settings is included, the EEPROM size is fixed; if an EEPROM
size option (-s, -b or -B) is included on the command line, it must match the
config-set EEPROM size, otherwise the tool bails out with an error.  If no
eeprom setting is included in the config file, then any EEPROM size may be
selected with command line options, and if no such options are included on the
command line either, then the final default is 93C46.

Preparing config files for boards
---------------------------------

If you have a specific board design with an FTDI chip and are preparing an
EEPROM config file for your board, our recommendation is to include ftdi-chip
and eeprom lines in your config file, naming the specific FTDI chip and the
specific EEPROM size on your board.  By doing so, you reduce the possibility
that someone will misprogram your EEPROM by selecting the wrong generator tool
or the wrong EEPROM size.

The alternative approach of leaving these settings unspecified or underspecified
should be used for unfinished EEPROM config templates or examples, or configs
that can be sensibly loaded into many different boards that may vary in FT2232x
chip choice and EEPROM size.