SPD(serial presence detect),即串行存在检测,是DIMM的相关描述信息。
在每根内存条上,都有一份SPD数据,这份数据保存在一个可擦写的eeprom芯片中。SPD数据记录了该内存的许多重要信息,诸如内存的芯片及模组厂商、工作频率、工作电压、速度、容量、电压与行、列地址带宽等参数。SPD数据一般都是在出厂前,由DIMM制造商根据内存芯片的实际性能写入到eeprom芯片中。
SPD 中的数据主要是供 BIOS 在引导阶段给初始化内存时使用的,如果数据有误或者没有数据将导致内存初始化失败。随着技术发展尤其是 CXL 技术的发展,出现了多种支持 DDR 扩展的外设,这种情况下 SPD 还可能被外设的 fw 读取来进行初始化内存。
注:如无特别说明,本文档基于 SPD5 进行说明。
不同类型的DDR,他们的SPD数据长度和格式可能会不一样,比如:
但是,在这些不同长度的SPD数据中,有一些字段偏移可能是不兼容的。对于一些很基础的信息,他们的格式是一致的,比如DDR4与DDR3中,第0-5字节,他们表示的含义是相同的,其他则可能就不同。
下图是 DDR5 中 SPD 的数据布局:
其中 annexes N.1.x 表示不同类型的内存设备会有不同的格式,具体参考这些章节。
DDR5 可以划分为多个 block:
共 16 个 bolck, 每个 block 包含64bytes,是一个写保护单元。即在 DDR5 的 SPD 中,写保护是按照 block 来进行的。
DDR5 SPD Revision 按照 section 划分,每个 section 都有自己的 revision bytes。
需要注意的是,revision 分成两个部分 x.y,两个部分的数值都是只增不减,如果高位增加,低位也不会降低。比如版本从 1.2 升到 1.3,下一版升高版本时应该是 3.3。
即使在编码级别增加之后,添加级别也不会降低。例如,如果当前 SPD 修订级别为 1.2,并且编码级别的更改获得批准,则下一个修订级别将是 2.2。如果对修订 2.2 的补充获得批准,下一个修订将是 2.3。然而,编码级别的更改极为罕见,因为它们会导致与旧系统不兼容。
这里只显示几个常用的字节的数据格式,所有的数据请查看《JESD400-5_DDR5 Serial Presence Detect(SPD) Contents_Rev 0.89》
Byte 0 (0x000): Number of Bytes in SPD Device
这个字节表示 SPD 的数据长度。
Byte 1 (0x001): SPD Revision for Base Configuration Parameters
这个字节表示 SPD 中 EEPROM 匹配的版本,分为 Encoding Level (高半字节) 和 Additions Level (低半字节)两个部分。其中 Encoding Level 表示发行版本,软件需要读取这部分内容以确定其合法性以及准确性。Additions Level 是可选的,定义了哪些附加字节或属性位。
Byte 2 (0x002): Key Byte / Host Bus Command Protocol Type
这个 byte 表示DDR 的版本和类别等信息,BIOS 会根据这个 byte 的值来确定如何解析整个 EEPROM 的内容。
同时这个 byte 也决定了后面的 block 3-6 里面包含的内容。
Byte 3 (0x003): Key Byte / Module Type
这个 byte 表示了 SPD 对应的内存的类型,分为3段表示,bit[3:0]表示 SDRAM 类型,bit[6:4] 表示内存设备类型, bit[7]区分有无混合类型。
所谓混合类型是指该内存设备除 SDRAM 外还有其他模块用于数据存储。
其他 EEPROM 内容参见: JESD400-5 DDR5 Serial Presence Detect (SPD) Contents
前面描述的 1KB 内容是 EEPROM 的数据,这些数据保存了关于 SDRAM 和 DDR 的配置和性能信息等。对于 SPD 和 EEPROM 本身,还有128个寄存器(每个寄存器 8bits) "MR0 - MR127" 来进行描述和配置。
这里只记录部分用到过的寄存器的内容。
MR0 - Device Type; Most Significant Byte
MR1 - Device Type; Least Significant Byte
MR11 - I2C Legacy Mode Device Configuration
这个寄存器设置了 SPD 作为 I2C Slave 时使用的地址模式,1Byte地址或者2Byte地址。使用 1Byte 地址模式时,I2C 的数据包中地址仅占 7bits,只能访问到 128 bytes 范围内的内容,而 EEPROM 占 1KB,所以后面要使用 page 来进行页面选择。使用 2 Bytes 地址模式时,I2C 数据包地址占两个 Bytes,可以直接访问所有的偏移,不需要使用 page。
Note1:Once any register bit is set to ‘1’, it can only be cleared when the SPD5 Hub device is in offline tester mode of operation.
Note2:The write (or update) transaction to this register must be followed by STOP operation to allow SPD5 Hub device to update the setting.
其他寄存器内容参见:JESD300-5 SPD5118, SPD5108 Hub and Serial Presence Detect Device Standard
访问 SPD 指的是访问 SPD 内的寄存器或者 EEPROM。前面的内容提到,SPD5 有128个配置寄存器,一个 1KB 大小的 EEPROM,这两者空间的偏移都是从 0x00 开始(寄存器:0x00 - 0x7F,EEPROM:0x000 - 0x3FF)。但是这两个空间又同时不在系统的 MMIO 空间中,要使用 I2C/I3C 协议来对它们进行访问,此时如何区分这两个空间就很关键了。
系统软件对 SPD 的访问一般是通过 I2C/I3C 协议来进行的,SPD 作为 Slave device MIPI 分配有固定的 address。SPD 的 7-bit Address 中高 4 位固定为 ‘a’,低 3 位根据 Hub 的不同有不同的值。其地址分配如下:
前面提到的 EEPROM 和 SPD Registers 都属于 SPD5 Hub Device 本身的内容,所以它们使用的 Slave Address 就是 0xaX。后面我们我们还将看到 PMIC 和 RCD 等内容则属于 SPD5 Hub Local Device,此时可以将 SPD5 理解为一个 Hub,其下还可以挂接不同的 PMIC 和 RCD 等作为下游设备挂接到 SPD5 Hub 下,理所当然地它们拥有不同的 Slave Address。
I2C 访问 SPD5 Hub Device 和 访问 SPD5 Hub Local Device 使用的协议包格式是不一样的,这里主要讲前者。
前面讲 MR11 寄存器时有提到,SPD5 支持两种地址模式,默认情况下采用的是 2bytes 模式.如果主动修改,也是可以使用 1byte 模式的,但只能应用于 SPD5 Hub Device,不能应用于 PMIC 和 RCD 等。所以 I2C 协议的数据包也会有两种格式。
SPD 寄存器和 EEPROM 的偏移都是从 0 开始的,所以数据包中定义了一个 MemReg bit 来表示访问的是哪一个区域。
注:SPD4 或之前只有 1byte 模式一种。
MemReg = 0 : 访问 SPD 寄存器,此时 Blk Addr 被当作高位地址
MemReg = 1 : 访问 EEPROM
1byte mode write
这是 1bytes 模式下,Host 写操作的数据包,只取 Address 的低 6 位,Blk Addr[0] 表示取 page 的低 128bytes 还是高 128bytes。由于最多只能访问 256 bytes,要访问其他 EEPROM 位置需要首先向 MR11[2:0] 写入对应的 page 值。
注:这里的 Blk Addr[0] 和 Address[5:0] 可以看作一个 Address[6:0],这样就避免了分两个位置的麻烦。
其流程如下,注意 Start/Ack/Stop 等信号由硬件发出,不需要程序员参与:
2bytes mode write
可以看到,Address被划分到两个字节中,其中[6:0]与 MemReg 组成第一个字节,剩下的[10:7]保存在第二个字节内。对于 SPD5,2bytes 模式下会将地址限制在 1KB 以内(即0x0 - 0x3FF,地址占 10bits),所以这里的 Blk Addr[4] 的值是无效的。
流程如下:
使用 I2C 进行读操作时,先写入读取地址,再发起第二次通信进行数据读取。读数据时根据协议要求,第一字节 bit0 应该置1,但这是硬件会去完成的操作,对于软件,我们在写入第一个包后,只需从 I2C 数据寄存器中读取内容即可。
除了第一个消息中不包含要写入的数据,以及写完之后多一个读数据寄存器的步骤,读的操作与写操作基本一致,也通过 MemReg bit来表示读取 EEPROM 或 内部寄存器。
1byte mode read
我们只要关注前面 W=0 的部分即可。
2bytes mode read
Default Read Address Pointer Mode
除了上述两种读模式之外, SPD5 还提供了一个叫做“默认读”模式,主要是为了提高从同一地址读取关键数据的效率。在这种模式下,只要发送 Slave ID + 读取命令,不需要写入地址即可从某一地址连续读取数据。该地址在 I2C 初始化时即被写入到寄存器 MR18 中,且只能读取寄存器区域的内容。
相比于 2bytes mode,这种模式可以节省2个字节的包长度。
SPD 的数据按照 section 划分,每个 section 末尾会有两个字节的 CRC 校验值,表示该 section 的数据是否合法。如下图所示:
BIOS 在处理 SPD 时会按照以下步骤:
step1. 分析 SPD 数据合法性 : 按照图示,读取每一个 section 的 CRC 校验值,如果校验通过表示 SPD 合法。
step2. 判断 DDR type 是否正确 : 通过读取 byte2 来判断当前 DIMM 是否是目标类型。比如 byte2 = 0x12 表示 DDR5。
step3. 验证 SPD 兼容性 : SPD byte1 表示 SPD 的版本信息,当系统比较旧或者发生严重的错误时,强制要求系统停止初始化内存。SPD 版本的增加可能会影响到内部有效数据的长度,但是出于向后兼容的考虑,新的版本的内容通常能覆盖旧的版本。如果 BIOS 仅支持到 SPD 1.2,那么对于1.3 或以上版本的 SPD,BIOS 只能从中提取 1.2 版本定义的信息。
注:在 DDR5 SPD 中 SPD revision 只表示本段的版本,比如 byte1 表示 byte0-127的版本,其他的 section 都有自己单独 revison byte。这样可以使得各个 section 单独更新而不影响其他 section。
step4. 确定内存模块类型 : 这里的模块类型是指 RDIMM, UDIMM 等,由 byte3 表示。
Module Type | Byte 3 |
Solder Down | 0x0B |
UDIMM | 0x02 |
SO-DIMM | 0x03 |
RDIMM | 0x01 |
LRDIMM | 0x04 |
DDIMM | 0x07 |
NVDIMM-N Hybrid | 0x9x |
NVDIMM-P Hybrid | 0xAx |
step5. 确定内存基本配置 : 分析 byte0-127, 所有的模块类型都需要分析这部分内容。
step6. 配置标准的内存模块接口 : 分析 byte192 - 447。
一步一步带你理解DDR基本原理_百里杨的博客-CSDN博客_ddr层次
JESD400-5 DDR5 Serial Presence Detect (SPD) Contents
JESD300-5 SPD5118, SPD5108 Hub and Serial Presence Detect Device Standard