BIOS 在POST的過程中會透過SMBus 去讀取DIMM上的 EEPROM中的 SPD (serial presence detect) 的資訊來配置記憶體控制器(memory controller)。不太熟悉 SMBus的話可以先參考 初學 SMBus
在DDR4的時候,JEDEC 定義了一種新的非標準 EE1004 類型,SPD大小增加到4-Kbit (4 * 1024 / 8 = 512 Bytes),分為兩個Page,各256Bytes。(可以參考 4-Kbit Serial Presence Detect (SPD) EEPROM compatible with JEDEC EE1004 (st.com))
如果需要讀取資料,要採用切page的方式,使用一個Byte表示要讀取的位置。因此
- 讀取EEPROM 前256 Bytes的資料,需要切到page0
- 讀取EEPROM 後256 Bytes的資料,需要切到page1
如下圖,如果要讀EEPROM中的offset 0x135的位置,page和要帶入的offset關係可以套用以下公式:
#define EE1004_PAGE_SHIFT 8
page = offset >> EE1004_PAGE_SHIFT;
offset &= (1 << EE1004_PAGE_SHIFT) - 1;
page = 0x135 >>8 = 0x01 -->切到page1
offset = 0x135 & ((1<<8) -1) = 0x135 & 0xFF = 0x35 --> offset為 0x35
由此可知,讀取DDR4的SPD做法和DDR3差不多,只是多了切page的動作。切page的方式是對 0x36 (SPA0) 或 0x37 (SPA1) 的7 bits address寫入一個byte (這邊的data可以忽略,填0x00就好)。這個指令對照SMBus Spec 就是Send Byte
(*0x36 是7bit address, 要加上一個Wr bit=0 才會是最後送出的address,所以 0x36 <<1 | 0 = 0x6C)
切完page之後,就可以使用Read Byte將值讀出來,這邊Wr bit要記得設為1
最後讀出來的Data可以對照 JESD21-C Annex L: Serial Presence Detect for DDR4 SDRAM Modules 翻成明文
以上可以另外參考
----
最後,如果想要透過操作SMBus Controller 的方式將SPD給讀出來,步驟可以分為三個部分
- 初始化SMBus (只需要做一次)
- 切PAGE
- 讀SPD (可以用Byte、Byte Data或是Block)
初始化SMBus
// SMBus Controller
addr = PCI_BASE | (PCI_SMBUS_BUS << 16) | (PCI_SMBUS_DEV << 11) | (PCI_SMBUS_FUN << 8);
// Set the I/O Space enable bit
// PCICMD_OFFSET 0x04
outpd(0xCF8, addr + PCICMD_OFFSET);
data = inpd(0xCFC);
if ((data & 0x01) == 0)
{
outpd(0xCFC, data | 0x01);
}
// Set the HST_EN bit
// HOSTC_OFFSET 0x40
outpd(0xCF8, addr + HOSTC_OFFSET);
data = inpd(0xCFC);
if ((data & 0x01) == 0)
{
data = outpd(0xCFC, data | 0x01);
}
// Program the SMBus Base Address Register
// SMB_BASE_OFFSET 0x20
outpd(0xCF8, addr + SMB_BASE_OFFSET);
SMBBASE = inpd(0xCFC) & 0xFFE0;
切 PAGE
// Clear the status bits
// HST_STS (Host Status Register) 0x00
outp(SMBBASE + HST_STS, 0x1E);
// ee1004 set current page
// XMIT_SLVA (Transmit Slave Address Register) 0x04
// 0x6C for page0, and 0x6E for page1
outp(SMBBASE + XMIT_SLVA, 0x6C);
// Data is ignored
// HST_CMD (Host Command Register) 0x03
outp(SMBBASE + HST_CMD, 0x00);
// Execute the Byte command
// HST_CNT (Host Control Register) 0x02
outp(SMBBASE + HST_CNT, 0x44);
// Error handling
讀SPD (這邊使用Byte Data)
// Clear the status bits
// HST_STS (Host Status Register) 0x00
outp(SMBBASE + HST_STS, 0x1E);
// Set Address
// XMIT_SLVA (Transmit Slave Address Register) 0x04
outp(SMBBASE + XMIT_SLVA, Addr << 1 | 1);
// HST_CMD (Host Command Register) 0x03
outp(SMBBASE + HST_CMD, offset2read);
// Execute the Byte Data command
// HST_CNT (Host Control Register) 0x02
outp(SMBBASE + HST_CNT, 0x48);
// Error handling
// Read data from Data0 register
// HST_D0 (Host Data 0 Register) 0x05
SPDData = inp(SMBBASE + HST_D0);
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。