Freescale QUICC Engine 固件上传¶
2007 Timur Tabi <timur at freescale.com>, Freescale Semiconductor
修订信息¶
2007年11月30日:版本 1.0 - 初始版本
I - 固件软件许可¶
每个固件文件都附带其自己的软件许可。有关特定许可的信息,请参阅随固件一起分发的许可文本。
II - 微代码可用性¶
固件文件通过各种渠道进行分发。部分文件可在 http://opensource.freescale.com 获取。对于其他固件文件,请联系您的 Freescale 代表或您的操作系统供应商。
III - 描述与术语¶
在本文档中,术语“微代码”(microcode)指组成实际 QE 微代码的一系列 32 位整数。
术语“固件”(firmware)指一个二进制 blob,它包含微代码以及其他以下数据:
描述微代码的用途
描述如何以及在哪里上传微代码
指定各种寄存器的值
包含供特定设备驱动程序使用的附加数据
固件文件是仅包含固件的二进制文件。
IV - 微代码编程细节¶
QE 架构允许每个 RISC 处理器的 I-RAM 中仅存在一个微代码。要替换任何当前的微代码,必须首先执行完整的 QE 复位(这会禁用微代码)。
QE 微代码通过以下步骤进行上传:
使用 IRAM.IADD 和 IRAM.IDATA 寄存器,将微代码置于 I-RAM 的特定位置。
根据固件是否需要拆分 I-RAM,将 CERCR.CIR 位设置为 0 或 1。拆分 I-RAM 仅对于具有多 RISC 处理器 QE 的 SOC(例如 8360)才有意义。拆分 I-RAM 允许每个处理器运行不同的微代码,从而有效地创建一个非对称多处理(AMP)系统。
将微代码中陷阱处理程序的地址加载到 TIBCR 陷阱寄存器中。
使用提供的值对 RSP.ECCR 寄存器进行编程。
如有必要,需要虚拟陷阱和扩展模式数据的设备驱动程序将使用它们。
虚拟微代码陷阱
这些虚拟陷阱是微代码中的条件分支。为了实现更高的灵活性并节省硬件陷阱,ROMcode 中引入了这些“软”临时机制。如果在 RAM 软件包中激活了新功能或正在修复问题,则应将其激活。此数据结构向微代码指示哪些虚拟陷阱处于活动状态。
此结构包含应用程序应复制到某些特定已定义位置的 6 个字。下表描述了该结构
---------------------------------------------------------------
| 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 |
---------------------------------------------------------------
扩展模式
这是一个双字位数组(64 位),定义了对软件驱动程序有影响的特殊功能。每一位都有其自己的影响,并为其关联的软件提供了特殊说明。下表描述了此结构
-----------------------------------------------------------------------
| 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 - 固件结构布局¶
Freescale 的 QE 微代码通常作为头文件提供。该头文件包含定义微代码二进制文件本身的宏,以及用于上传该微代码的其他一些数据。这些文件的格式不适合简单地包含到其他代码中。因此,需要一种更具可移植性的格式。本节定义了该格式。
微代码和相关数据没有分发头文件,而是嵌入到了一个二进制 blob 中。该 blob 被传递给 qe_upload_firmware() 函数,该函数解析 blob 并执行上传微代码所需的一切操作。
所有整数均为大端序。有关最新的实现信息,请参阅函数 qe_upload_firmware() 的注释。
此结构支持版本控制,结构的版本嵌入在结构本身中。为确保向前和向后兼容性,所有版本的结构必须在开头使用相同的“qe_header”结构。
- ‘header’(类型:struct qe_header)
‘length’ 字段是整个结构的大小(以字节为单位),包括其中嵌入的所有微代码以及 CRC(如果存在)。
‘magic’ 字段是一个包含字母 ‘Q’、‘E’ 和 ‘F’ 的三个字节的数组。这是一个标识符,指示此结构是 QE 固件结构。
‘version’ 字段是一个单字节,指示此结构的版本。如果需要更改结构的布局以支持其他类型的微代码,则也应更改版本号。
‘id’ 字段是一个以 null 结尾的字符串(适合打印),用于标识固件。
‘count’ 字段指示 ‘microcode’ 结构的数量。每个 RISC 处理器必须有且仅有一个 ‘microcode’ 结构。因此,该字段也表示此 SOC 的 RISC 处理器的数量。
‘soc’ 结构包含用于将微代码与 SOC 本身进行匹配的 SOC 编号和修订版本。通常,微代码加载程序应使用 SOC 编号和修订版本检查此结构中的数据,并且仅在匹配时才上传微代码。但是,并非所有平台都进行此项检查。
尽管不推荐,但您可以在 soc.model 字段中指定“0”以完全跳过 SOC 匹配。
‘model’ 字段是一个与实际 SOC 匹配的 16 位数字。‘major’ 和 ‘minor’ 字段分别是 SOC 的主修订号和次修订号。
例如,要匹配 8323,版本 1.0
soc.model = 8323
soc.major = 1
soc.minor = 0
‘padding’ 对于结构对齐是必需的。此字段确保 ‘extended_modes’ 字段对齐到 64 位边界。
‘extended_modes’ 是一个位域,定义了对设备驱动程序有影响的特殊功能。每一位都有其自己的影响,并为其关联的驱动程序提供特殊说明。此字段存储在 QE 库中,可供任何调用 qe_get_firmware_info() 的驱动程序使用。
‘vtraps’ 是一个包含 8 个字的数组,其中包含每个虚拟陷阱的虚拟陷阱值。与 ‘extended_modes’ 一样,此字段存储在 QE 库中,可供任何调用 qe_get_firmware_info() 的驱动程序使用。
- ‘microcode’(类型:struct qe_microcode)
每个 RISC 处理器都有一个 ‘microcode’ 结构。第一个 ‘microcode’ 结构对应第一个 RISC,依此类推。
‘id’ 字段是一个适合打印的以 null 结尾的字符串,用于标识此特定微代码。
‘traps’ 是一个包含 16 个字的数组,其中包含 16 个陷阱中每一个的硬件陷阱值。如果 trap[i] 为 0,则应忽略此特定陷阱(即不写入 TIBCR[i])。整个值将原样写入 TIBCR[i] 寄存器,因此请确保在必要时设置 EN 和 T_IBP 位。
‘eccr’ 是要编程到 ECCR 寄存器中的值。
‘iram_offset’ 是开始写入微代码的 IRAM 偏移量。
‘count’ 是微代码中 32 位字的数量。
‘code_offset’ 是从该结构开头到可以找到微代码本身的偏移量(以字节为单位)。第一个微代码二进制文件应位于 ‘microcode’ 数组之后。
‘major’、‘minor’ 和 ‘revision’ 分别是微代码的主版本号、次版本号和修订版本号。如果所有值都为 0,则忽略这些字段。
‘reserved’ 对于结构对齐是必需的。由于 ‘microcode’ 是一个数组,64 位的 ‘extended_modes’ 字段需要对齐到 64 位边界,而这只有在 ‘microcode’ 的大小是 8 字节的倍数时才能实现。为了确保这一点,我们添加了 ‘reserved’。
最后一个微代码之后是一个 32 位 CRC。可以使用以下算法计算它
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 - 用于创建固件文件的示例代码¶
可以从 http://opensource.freescale.com 找到一个 Python 程序,它用于从 Freescale 通常分发的头文件创建固件二进制文件。