| Freescale QUICC Engine Firmware Uploading |
| ----------------------------------------- |
| |
| (c) 2007 Timur Tabi <timur at freescale.com>, |
| Freescale Semiconductor |
| |
| Table of Contents |
| ================= |
| |
| I - Software License for Firmware |
| |
| II - Microcode Availability |
| |
| III - Description and Terminology |
| |
| IV - Microcode Programming Details |
| |
| V - Firmware Structure Layout |
| |
| VI - Sample Code for Creating Firmware Files |
| |
| Revision Information |
| ==================== |
| |
| November 30, 2007: Rev 1.0 - Initial version |
| |
| I - Software License for Firmware |
| ================================= |
| |
| Each firmware file comes with its own software license. For information on |
| the particular license, please see the license text that is distributed with |
| the firmware. |
| |
| II - Microcode Availability |
| =========================== |
| |
| Firmware files are distributed through various channels. Some are available on |
| http://opensource.freescale.com. For other firmware files, please contact |
| your Freescale representative or your operating system vendor. |
| |
| III - Description and Terminology |
| ================================ |
| |
| In this document, the term 'microcode' refers to the sequence of 32-bit |
| integers that compose the actual QE microcode. |
| |
| The term 'firmware' refers to a binary blob that contains the microcode as |
| well as other data that |
| |
| 1) describes the microcode's purpose |
| 2) describes how and where to upload the microcode |
| 3) specifies the values of various registers |
| 4) includes additional data for use by specific device drivers |
| |
| Firmware files are binary files that contain only a firmware. |
| |
| IV - Microcode Programming Details |
| =================================== |
| |
| The QE architecture allows for only one microcode present in I-RAM for each |
| RISC processor. To replace any current microcode, a full QE reset (which |
| disables the microcode) must be performed first. |
| |
| QE microcode is uploaded using the following procedure: |
| |
| 1) The microcode is placed into I-RAM at a specific location, using the |
| IRAM.IADD and IRAM.IDATA registers. |
| |
| 2) The CERCR.CIR bit is set to 0 or 1, depending on whether the firmware |
| needs split I-RAM. Split I-RAM is only meaningful for SOCs that have |
| QEs with multiple RISC processors, such as the 8360. Splitting the I-RAM |
| allows each processor to run a different microcode, effectively creating an |
| asymmetric multiprocessing (AMP) system. |
| |
| 3) The TIBCR trap registers are loaded with the addresses of the trap handlers |
| in the microcode. |
| |
| 4) The RSP.ECCR register is programmed with the value provided. |
| |
| 5) If necessary, device drivers that need the virtual traps and extended mode |
| data will use them. |
| |
| Virtual Microcode Traps |
| |
| These virtual traps are conditional branches in the microcode. These are |
| "soft" provisional introduced in the ROMcode in order to enable higher |
| flexibility and save h/w traps If new features are activated or an issue is |
| being fixed in the RAM package utilizing they should be activated. This data |
| structure signals the microcode which of these virtual traps is active. |
| |
| This structure contains 6 words that the application should copy to some |
| specific been defined. This table describes the structure. |
| |
| --------------------------------------------------------------- |
| | Offset in | | Destination Offset | Size of | |
| | array | Protocol | within PRAM | Operand | |
| --------------------------------------------------------------| |
| | 0 | Ethernet | 0xF8 | 4 bytes | |
| | | interworking | | | |
| --------------------------------------------------------------- |
| | 4 | ATM | 0xF8 | 4 bytes | |
| | | interworking | | | |
| --------------------------------------------------------------- |
| | 8 | PPP | 0xF8 | 4 bytes | |
| | | interworking | | | |
| --------------------------------------------------------------- |
| | 12 | Ethernet RX | 0x22 | 1 byte | |
| | | Distributor Page | | | |
| --------------------------------------------------------------- |
| | 16 | ATM Globtal | 0x28 | 1 byte | |
| | | Params Table | | | |
| --------------------------------------------------------------- |
| | 20 | Insert Frame | 0xF8 | 4 bytes | |
| --------------------------------------------------------------- |
| |
| |
| Extended Modes |
| |
| This is a double word bit array (64 bits) that defines special functionality |
| which has an impact on the software drivers. Each bit has its own impact |
| and has special instructions for the s/w associated with it. This structure is |
| described in this table: |
| |
| ----------------------------------------------------------------------- |
| | Bit # | Name | Description | |
| ----------------------------------------------------------------------- |
| | 0 | General | Indicates that prior to each host command | |
| | | push command | given by the application, the software must | |
| | | | assert a special host command (push command)| |
| | | | CECDR = 0x00800000. | |
| | | | CECR = 0x01c1000f. | |
| ----------------------------------------------------------------------- |
| | 1 | UCC ATM | Indicates that after issuing ATM RX INIT | |
| | | RX INIT | command, the host must issue another special| |
| | | push command | command (push command) and immediately | |
| | | | following that re-issue the ATM RX INIT | |
| | | | command. (This makes the sequence of | |
| | | | initializing the ATM receiver a sequence of | |
| | | | three host commands) | |
| | | | CECDR = 0x00800000. | |
| | | | CECR = 0x01c1000f. | |
| ----------------------------------------------------------------------- |
| | 2 | Add/remove | Indicates that following the specific host | |
| | | command | command: "Add/Remove entry in Hash Lookup | |
| | | validation | Table" used in Interworking setup, the user | |
| | | | must issue another command. | |
| | | | CECDR = 0xce000003. | |
| | | | CECR = 0x01c10f58. | |
| ----------------------------------------------------------------------- |
| | 3 | General push | Indicates that the s/w has to initialize | |
| | | command | some pointers in the Ethernet thread pages | |
| | | | which are used when Header Compression is | |
| | | | activated. The full details of these | |
| | | | pointers is located in the software drivers.| |
| ----------------------------------------------------------------------- |
| | 4 | General push | Indicates that after issuing Ethernet TX | |
| | | command | INIT command, user must issue this command | |
| | | | for each SNUM of Ethernet TX thread. | |
| | | | CECDR = 0x00800003. | |
| | | | CECR = 0x7'b{0}, 8'b{Enet TX thread SNUM}, | |
| | | | 1'b{1}, 12'b{0}, 4'b{1} | |
| ----------------------------------------------------------------------- |
| | 5 - 31 | N/A | Reserved, set to zero. | |
| ----------------------------------------------------------------------- |
| |
| V - Firmware Structure Layout |
| ============================== |
| |
| QE microcode from Freescale is typically provided as a header file. This |
| header file contains macros that define the microcode binary itself as well as |
| some other data used in uploading that microcode. The format of these files |
| do not lend themselves to simple inclusion into other code. Hence, |
| the need for a more portable format. This section defines that format. |
| |
| Instead of distributing a header file, the microcode and related data are |
| embedded into a binary blob. This blob is passed to the qe_upload_firmware() |
| function, which parses the blob and performs everything necessary to upload |
| the microcode. |
| |
| All integers are big-endian. See the comments for function |
| qe_upload_firmware() for up-to-date implementation information. |
| |
| This structure supports versioning, where the version of the structure is |
| embedded into the structure itself. To ensure forward and backwards |
| compatibility, all versions of the structure must use the same 'qe_header' |
| structure at the beginning. |
| |
| 'header' (type: struct qe_header): |
| The 'length' field is the size, in bytes, of the entire structure, |
| including all the microcode embedded in it, as well as the CRC (if |
| present). |
| |
| The 'magic' field is an array of three bytes that contains the letters |
| 'Q', 'E', and 'F'. This is an identifier that indicates that this |
| structure is a QE Firmware structure. |
| |
| The 'version' field is a single byte that indicates the version of this |
| structure. If the layout of the structure should ever need to be |
| changed to add support for additional types of microcode, then the |
| version number should also be changed. |
| |
| The 'id' field is a null-terminated string(suitable for printing) that |
| identifies the firmware. |
| |
| The 'count' field indicates the number of 'microcode' structures. There |
| must be one and only one 'microcode' structure for each RISC processor. |
| Therefore, this field also represents the number of RISC processors for this |
| SOC. |
| |
| The 'soc' structure contains the SOC numbers and revisions used to match |
| the microcode to the SOC itself. Normally, the microcode loader should |
| check the data in this structure with the SOC number and revisions, and |
| only upload the microcode if there's a match. However, this check is not |
| made on all platforms. |
| |
| Although it is not recommended, you can specify '0' in the soc.model |
| field to skip matching SOCs altogether. |
| |
| The 'model' field is a 16-bit number that matches the actual SOC. The |
| 'major' and 'minor' fields are the major and minor revision numbers, |
| respectively, of the SOC. |
| |
| For example, to match the 8323, revision 1.0: |
| soc.model = 8323 |
| soc.major = 1 |
| soc.minor = 0 |
| |
| 'padding' is necessary for structure alignment. This field ensures that the |
| 'extended_modes' field is aligned on a 64-bit boundary. |
| |
| 'extended_modes' is a bitfield that defines special functionality which has an |
| impact on the device drivers. Each bit has its own impact and has special |
| instructions for the driver associated with it. This field is stored in |
| the QE library and available to any driver that calles qe_get_firmware_info(). |
| |
| 'vtraps' is an array of 8 words that contain virtual trap values for each |
| virtual traps. As with 'extended_modes', this field is stored in the QE |
| library and available to any driver that calles qe_get_firmware_info(). |
| |
| 'microcode' (type: struct qe_microcode): |
| For each RISC processor there is one 'microcode' structure. The first |
| 'microcode' structure is for the first RISC, and so on. |
| |
| The 'id' field is a null-terminated string suitable for printing that |
| identifies this particular microcode. |
| |
| 'traps' is an array of 16 words that contain hardware trap values |
| for each of the 16 traps. If trap[i] is 0, then this particular |
| trap is to be ignored (i.e. not written to TIBCR[i]). The entire value |
| is written as-is to the TIBCR[i] register, so be sure to set the EN |
| and T_IBP bits if necessary. |
| |
| 'eccr' is the value to program into the ECCR register. |
| |
| 'iram_offset' is the offset into IRAM to start writing the |
| microcode. |
| |
| 'count' is the number of 32-bit words in the microcode. |
| |
| 'code_offset' is the offset, in bytes, from the beginning of this |
| structure where the microcode itself can be found. The first |
| microcode binary should be located immediately after the 'microcode' |
| array. |
| |
| 'major', 'minor', and 'revision' are the major, minor, and revision |
| version numbers, respectively, of the microcode. If all values are 0, |
| then these fields are ignored. |
| |
| 'reserved' is necessary for structure alignment. Since 'microcode' |
| is an array, the 64-bit 'extended_modes' field needs to be aligned |
| on a 64-bit boundary, and this can only happen if the size of |
| 'microcode' is a multiple of 8 bytes. To ensure that, we add |
| 'reserved'. |
| |
| After the last microcode is a 32-bit CRC. It can be calculated using |
| this algorithm: |
| |
| u32 crc32(const u8 *p, unsigned int len) |
| { |
| unsigned int i; |
| u32 crc = 0; |
| |
| while (len--) { |
| crc ^= *p++; |
| for (i = 0; i < 8; i++) |
| crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); |
| } |
| return crc; |
| } |
| |
| VI - Sample Code for Creating Firmware Files |
| ============================================ |
| |
| A Python program that creates firmware binaries from the header files normally |
| distributed by Freescale can be found on http://opensource.freescale.com. |