内存标签解析DDR5 SPD读取

DDR(Double Data Rate)SPD(Serial Presence Detect)是一种存储在计算机内存模块上的小型EEPROM芯片,用于存储有关内存模块制造商、型号、速度等信息。SPD芯片通过计算机的内存控制器与主板通信,提供关键的信息以确保内存模块能够正确运行。

SPD芯片中存储的信息包括但不限于:

- 制造商信息:制造商名称、产品型号等

- 内存规格:容量、速度等

- 时序参数:内存模块的时序设置,如CAS延迟、RAS预充电时间等

- 校准信息:内存模块的校准数据,用于确保内存稳定运行

DDR4 SPD:

DDR5 :

Byte 2 (0x002): Key Byte / Host Bus Command Protocol Typ

Byte 4 (0x004): First SDRAM Density and Package

SPD Dump 实例:  16 G 单Rank

Dump bytes[SDP Info]: 0001: RDIMM

30 10 12 01 04 00 20 62 00 00 00 00 B0 02 01 00

00 00 00 00 A0 01 F2 03 7A 0D 00 00 00 00 80 3E

80 3E 80 3E 00 7D 80 BB 30 75 27 01 A0 00 82 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 88 13 08 88 13 08 20 4E 20 10

27 10 15 34 20 10 27 10 C4 09 04 4C 1D 0C 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

10 00 80 B3 80 21 0B 2A 81 12 00 00 00 00 00 00

00 00 80 B3 C0 12 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 11 21 03 81 00 32 00 00 00 00

80 B3 80 33 00 00 00 00 2E 4E 55 00 01 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

SPD Socket 0 Channel 11 Dimm 0: 0x00091d18

0xC0 :

10 00 80 B3 80 21 0B 2A 81 12 00 00 00 00 00 00

00 00 80 B3 C0 12 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 11 21 03 81 00 32 00 00 00 00

80 B3 80 33 00 00 00 00 2E 4E 55 00 01 00 00 00

Module Manufacturer ID Code     : ce80(Samsung)

Module Revision Code            : 0000

Module Part Number              : M321R2GA3BB6-CQKET

Module Serial Number            : 450e2416

Module Manufacturing Date       : 23-15(year-week)

DRAM Manufacturer ID Code       : ce80(Samsung)

DRAM stepping                   : 0095

SPD  Manufacturer ID Code       : b380

SPD  Device Type                : 0080

SPD  Revision Number            : 0021

PMIC 0 Manufacturer ID Code     : 2a0b

PMIC 0 Device Type              : 0081

PMIC 0 Revision Number          : 0012

PMIC 1 Manufacturer ID Code     : 0000

PMIC 1 Device Type              : 0000

PMIC 1 Revision Number          : 0000

PMIC 2 Manufacturer ID Code     : 0000

PMIC 2 Device Type              : 0000

PMIC 2 Revision Number          : 0000

TS Manufacturer ID Code         : b380

TS Device Type                  : 00c0

TS Revision Number              : 0012

RCD Manufacturer ID Code        : b380(Renesa)

RCD Device Type                 : 0080

RCD Revision Number             : 0033

DB ID Code                      : 0000

DB Device Type                  : 0000

DB Revision Number              : 0000

[Socket 0 Channel 0 Dimm 0] Manu:Samsung, PN:M321R2GA3BB6-CQKET, Size:16GB, 1Rx8

DDR5, ECC:Yes, SN:450E22EF

0x200

80 CE 04 23 15 45 0E 24 17 4D 33 32 31 52 32 47

41 33 42 42 36 2D 43 51 4B 45 54 20 20 20 20 20

20 20 20 20 20 20 20 00 80 CE 95 54 30 55 39 30

30 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

01 01 01 01 01 01 00 00 80 00 00 00 00 00 00 00

Byte 514 (0x202): Module Manufacturing Location
Bytes 515~516 (0x203~0x204): Module Manufacturing Date

Bytes 517~520 (0x205~0x208): Module Serial Number

Bytes 521~550 (0x209~0x226): Module Part Number

BIOS中读取SPD 信息

DDR5 :

HgpiStatus = HgpiReadSpd (0, &ReadSpd);

HGPI_STATUS

HgpiReadSpd  (

  IN       UINTN                   FcnData,

  IN OUT   HGPI_READ_SPD_PARAMS   *ReadSpd

  )

{

  EFI_PEI_SERVICES                 **PeiServices;

  PEI_HYGON_PLATFORM_DIMM_SPD_PPI  *PlatformDimmPpi;

  EFI_STATUS                       Status;

  HGPI_STATUS                      HgpiStatus;

  HYGON_MEMORY_INIT_COMPLETE_PPI   *MemoryInitCompletePpiPtr;

  UINT8                            Socket;

  UINT8                            Channel;

  UINT8                            Dimm;

  UINT16                           SpdSize;

  PeiServices = (EFI_PEI_SERVICES **)GetPeiServicesTablePointer ();

  Socket  = ReadSpd->SocketId;

  Channel = ReadSpd->MemChannelId;

  Dimm    = ReadSpd->DimmId;

  IDS_HDT_CONSOLE (MAIN_FLOW, "      HgpiReadSpd Entry\n");

  HgpiStatus = HGPI_SUCCESS;

  SpdSize = PcdGetBool (PcdDDR5Enable) ? DDR5_SPD_SIZE : DDR4_SPD_SIZE;

  if (PcdGetBool (PcdHgpiInternalSpdInfo)) {

    // get spd data from fixed buffer

    // MemInitReadSpdBuffer (ReadSpd);

  } else if (PcdGetBool (PcdHgpiSpdUseHpobData)) {

    Status = (*PeiServices)->LocatePpi (

                               PeiServices,

                               &gHygonMemoryInitCompletePpiGuid,

                               0,

                               NULL,

                               &MemoryInitCompletePpiPtr

                               );

    if (EFI_SUCCESS != Status) {

      IDS_HDT_CONSOLE (MAIN_FLOW, "gHygonMemoryInitCompletePpiGuid Not Found.\n");

      return HGPI_ERROR;

    }

    if (MemoryInitCompletePpiPtr->HygonDimmSpInfo.DimmSpdInfo[Socket][Channel][Dimm].DimmPresent) {

      if (MemoryInitCompletePpiPtr->HygonDimmSpInfo.DimmSpdInfo[Socket][Channel][Dimm].SpdDataPtr != NULL) {

        LibHygonMemCopy (

          ReadSpd->Buffer,

          MemoryInitCompletePpiPtr->HygonDimmSpInfo.DimmSpdInfo[Socket][Channel][Dimm].SpdDataPtr,

          SpdSize,

          &ReadSpd->StdHeader

          );

        IDS_HDT_CONSOLE (MAIN_FLOW, "Get Spd Data success.\n");

        return HGPI_SUCCESS;

      } else {

        IDS_HDT_CONSOLE (MAIN_FLOW, "Dimm present, but no SPD data.\n");

        return HGPI_ERROR;

      }

    } else {

      IDS_HDT_CONSOLE (MAIN_FLOW, "Dimm not present.\n");

      return HGPI_ERROR;

    }

  } else {

    //

    // Locate DIMM SPD read PPI.

    //

    Status = (**PeiServices).LocatePpi (

                               PeiServices,

                               &gHygonPlatformDimmSpdPpiGuid,

                               0,

                               NULL,

                               &PlatformDimmPpi

                               );

    if (EFI_ERROR (Status)) {

      IDS_HDT_CONSOLE (MAIN_FLOW, "       PlatformDimmSpdRead.LocatePpi %r\n", Status);

      return HGPI_ERROR;

    }

    //

    // Invoke SPD Read

    //

    Status = PlatformDimmPpi->PlatformDimmSpdRead (PeiServices, PlatformDimmPpi, ReadSpd);

    IDS_HDT_CONSOLE (MAIN_FLOW, "       PlatformDimmSpdRead Exit %r\n", Status);

    if (!EFI_ERROR (Status)) {

      HgpiStatus = HGPI_SUCCESS;

    } else {

      HgpiStatus = HGPI_ERROR;

    }

  }

  return HgpiStatus;

}

/// HPOB SPD Data for each DIMM.

typedef struct _HPOB_SPD_STRUCT

{

  UINT8              SocketNumber;  ///< Indicates the socket number

  UINT8              ChannelNumber; ///< Indicates the channel number

  UINT8              DimmNumber;    ///< Indicates the channel number

  UINT8              PageAddress;   ///< Indicates the 256 Byte EE Page the data belongs to

  // 0 = Lower Page

  // 1 = Upper Page

  TECHNOLOGY_TYPE    Technology; ///< Indicates the type of Technology used in SPD

                                 ///< DDR3_TECHNOLOGY = Use DDR3 DIMMs

                                 ///< DDR4_TECHNOLOGY = Use DDR4 DIMMs

                ///<   DDR5_TECHNOLOGY = Use DDR5 DIMMs

                                 ///< LPDDR3_TECHNOLOGY = Use LPDDR3

  BOOLEAN            DimmPresent;   // < Indicates if the DIMM is present

  UINT8              MuxPresent;    ///< SpdMux Present or not. if 1, then yes otherwise no

  UINT8              MuxI2CAddress; ///< MuxI2cAddress

  UINT8              MuxChannel;    ///< MuxChannel no.

  UINT32             Address;       ///< SMBus address of the DRAM

  UINT32             SerialNumber;  ///< DIMM Serial Number

  UINT32             DeviceWidth:3;         ///< Device Width i.e. x4, x8, x16 and x32

  UINT32             DpprSupported:2;       ///< Dppr Support Present

  UINT32             SpprSupported:1;       ///< Sppd Support Present

  UINT32             Reserved:26;           ///< Reserved for Future Use

  UINT8              Data[1024];            ///< Buffer for 1024 Bytes of SPD data from DIMM

} HPOB_SPD_STRUCT;

使用Smbus Controller

// SMBus Controller   bdf  0:0B:00  Fch 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;

// 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

PCI 设备的BDF 通过lspci  -vvv | grep -i  smbus 获取BDF

PCI_BASE =0x80000000

addr = PCI_BASE | (PCI_SMBUS_BUS << 16) | (PCI_SMBUS_DEV << 11) | (PCI_SMBUS_FUN << 8);

汇编方式读取:

 ;----------smbus 访问规范--------

    call iodelay

    mov dx,sm_base  ;SMbus 的基地址

    add dx,00h      ;status register

    mov al,0feh     ;

    out dx,al

    call iodelay    ;延时

    mov dx,sm_base

    add dx,04h       ;slave address register

    mov ax,sm_devnum ;从设备地址:a0/a2/a4/a6 ,sm_devnum=a0h

    or al,01h        ;末位:1 - 表示读

    out dx,al

    call iodelay

    mov dx,sm_base

    add dx,03h       ;command register

    mov ax,sm_regnum ;寄存器索引

    out dx,al

    call iodelay

    inc sm_regnum

    mov dx,sm_base

    add dx,02h       ;control register

    mov al,48h       ;设置读写模式:字节(48h)、字(4ch)、块(54h)

    out dx,al

    call iodelay

    call iodelay;

    mov dx,sm_base

    add dx,00h

    in al,dx;

    mov dx,sm_base

    add dx,05h      ;data0 register

    in al,dx        ;回读数据

    push ax

mov bl,0fh

    call print_al

    call print_blank

    call print_blank

    pop ax

    mov es:[di],al  ;数据保存到buffer 中

    inc di

    cmp sm_regnum,07fh

    ja endsm        ;128-byte  读完

    jmp nextch

endsm:                    ;读完结束,打印buffer 后,结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小菜鸟-BIOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值