dimm-spd-reader: fix PMIC type detection from SPD

Add support for identifying PMIC unknown state as 0xFF.

Update PMIC SPD detection flow to read SPD registers 0x200, 0x204, and 0x208. Check bit7 to determine whether the PMIC is installed, and use SPD bit[3:0] as the PMIC type.

Also update the IPMI error handling path to return completion code 0x07 for command 0x6c when PMIC detection fails or the PMIC type is unknown.
This commit is contained in:
Your Name
2026-04-27 10:01:06 +08:00
parent 182a0516ac
commit 0cc0c96893
6 changed files with 697 additions and 68 deletions
+425
View File
@@ -0,0 +1,425 @@
From 182a0516acfeffabf6f2ec863d078d3ef72b0265 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Thu, 23 Apr 2026 17:48:19 +0800
Subject: [PATCH] LUXSHARE_2026041701
---
.../dimm/dimm-spd-reader/dimmSpdReader.cpp | 281 ++++++++++++++----
1 file changed, 229 insertions(+), 52 deletions(-)
diff --git a/meta-luxshare/meta-bhs/recipes-phosphor/dimm/dimm-spd-reader/dimmSpdReader.cpp b/meta-luxshare/meta-bhs/recipes-phosphor/dimm/dimm-spd-reader/dimmSpdReader.cpp
index cd730713..7438cbd3 100755
--- a/meta-luxshare/meta-bhs/recipes-phosphor/dimm/dimm-spd-reader/dimmSpdReader.cpp
+++ b/meta-luxshare/meta-bhs/recipes-phosphor/dimm/dimm-spd-reader/dimmSpdReader.cpp
@@ -346,7 +346,7 @@ static int i3cWriteRead(std::string& i3cDev, uint8_t wBuf[], uint16_t wLen,
std::cout << "i3c data to write:" << std::endl;
for(int i=0; i<wLen; i++)
{
- std::cout << "wBuf[" << i << "]: " << (int)wBuf[i] << " ";
+ std::cout << "wBuf[" << i << "]: 0x" << std::hex << (int)wBuf[i] << std::dec << " ";
}
std::cout << std::endl;
}
@@ -391,8 +391,12 @@ static int i3cWriteRead(std::string& i3cDev, uint8_t wBuf[], uint16_t wLen,
if constexpr (debug)
{
- std::cout << "i3c received data:" << std::endl;
- std::cout << "rBuf[0]: " << (int)rBuf[0] << std::endl;
+ std::cout << "i3c received data:\n";
+ for (int i = 0; i < (int)rLen; i++)
+ {
+ std::cout << "rBuf[" << i << "]: 0x" << std::hex << (int)rBuf[i] << std::dec << " ";
+ }
+ std::cout << "\n";
}
close(fd);
@@ -452,7 +456,8 @@ int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
uint8_t index[] = {0xc8, 0xcc, 0xd0};
uint16_t wLen = 2;
- uint8_t wrBuf[] = {0, 0};
+//Jim debug uint8_t wrBuf[] = {0, 0};
+ uint8_t wrBuf[] = {0, 0, 0}; //Jim debug
uint8_t rdBuf[] = {0};
uint16_t rLen = 1;
int spd = NUM_TO_SPD(rank);
@@ -494,6 +499,101 @@ int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
gotType[cpuid][rank] = true;
+//Jim debug+S
+
+//----------------------------------------------------------------------------
+//A. 1B Write R30 = 0x84 // 1 byte format, set 2 byte mode
+//B. 2B Read R0030 //check 2 byte mode
+// if(R0030 == 0x84)
+// 2 byte mode + 1ms delay: R30 success
+// Else // Original 2 byte mode
+// C. 2B Write R0030 = 0x84
+// D. 2B Read R0030
+// if(R0030 == 0x84) //check 2 byte mode
+// 2 byte mode + 1ms delay: R30 success
+ if (pmicType[cpuid][rank] == PMIC5030)
+ {
+
+ int pmic = NUM_TO_PMIC(rank);
+ std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
+
+ if constexpr (debug)
+ {
+ std::cout << "is PMIC5030"<< std::endl;
+ }
+ // 1. 1B Write R30 = 0x84
+ wLen = 2;
+ rLen = 0;
+ wrBuf[0] = 0x30; wrBuf[1] = 0x84;
+ rdBuf[0] = 0x00;
+ ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
+ if (ret < 0)
+ {
+ return -1;
+ }
+
+ if constexpr (debug)
+ {
+ std::cout << "first 1B Write R30 = 0x84" << std::endl;
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(9));
+
+ // 2. 2B Read R0030
+ wLen = 2;
+ rLen = 1;
+ wrBuf[0] = 0x30; wrBuf[1] = 0x00;
+ rdBuf[0] = 0x00;
+ ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
+ if (ret < 0)
+ {
+ return -1;
+ }
+
+ if constexpr (debug)
+ {
+ std::cout << "2B Read R0030 = 0x" << std::hex << (int)rdBuf[0] << std::endl;
+ }
+
+
+ // Successful switch to 2 Byte mode
+ if(rdBuf[0] == 0x84)
+ {
+ if constexpr (debug)
+ {
+ std::cout << "Is 2 Byte mode" << std::endl;
+ }
+ }
+ // It was originally 2 bytes mode
+ else
+ {
+ //C2-2. 2B Write R30 = 0x84
+ wrBuf[0] = 0x30; wrBuf[1] = 0x00; wrBuf[2] = 0x84;
+ wLen = 3;
+ rLen = 0;
+ ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(9));
+ //C2-2. 2B Read R30 = 0x84
+ wrBuf[0] = 0x30; wrBuf[1] = 0x00;
+ wLen = 2;
+ rLen = 1;
+ ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
+ if constexpr (debug)
+ {
+ std::cout << "2B Read R0030 = " << std::hex << (int)rdBuf[0] << std::endl;
+ }
+
+ //Force the use of 1-byte mode
+ if(rdBuf[0] != 0x84)
+ {
+ twoByteMode[cpuid][rank] = false;
+ std::cout << "Force the use of 1-byte mode" << std::endl;
+ }
+
+ }
+ }
+
+//Jim debug+E
if constexpr (debug)
{
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
@@ -635,9 +735,11 @@ int DIMMSpdReader::getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmDat
int index = (pmicType[cpuid][rank] == PMIC5030) ? 6 : 4;
for(int i=0; i<index; i++) {
- rLen = 1;
+ //Write R30
+ rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
if(twoByteMode[cpuid][rank])
{
+ adcValue = 0x4; //Jim debug, PMIC5030 fixed the 2 byte mode + 1ms
wrBuf[2] = adcValue | adcSel[i];
wLen = 3;
}
@@ -652,8 +754,14 @@ int DIMMSpdReader::getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmDat
{
return -1;
}
-
- std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
+//Jim debug std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
+//Jim debug+S
+ // For Renesas requirements, the JESD spec PMIC5030 needs a 9ms delay.
+ if(pmicType[cpuid][rank] == PMIC5030)
+ std::this_thread::sleep_for(std::chrono::milliseconds(9));
+ else
+ std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
+//Jim debug+E
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
rLen = 1;
@@ -700,6 +808,7 @@ static double calStep31CurPower(int index, const uint8_t (&temp)[8])
return result;
}
+
int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
{
int ret = -1;
@@ -719,7 +828,8 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
uint8_t adcSelect[] = {0x1b, 0, 0};
uint16_t curOut[8];
uint8_t temp[8];
- uint8_t rdBuf[] = {0};
+ uint8_t rdBuf[] = {0, 0, 0, 0, 0, 0, 0, 0}; //Jim debug, For Renesas requirements, I3C command: Continuously read R100~R107
+//Jim debug uint8_t rdBuf[] = {0};
uint8_t wrBuf[] = {0, 0};
int pmic = NUM_TO_PMIC(rank);
@@ -776,7 +886,7 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
adcSelect[1] = rdBuf[0] & 0xbf; //Read current
wLen = 2;
}
-
+ rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
if (ret < 0)
{
@@ -785,19 +895,34 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
- for(int i=0; i<index; i++) {
- rLen = 1;
- rdBuf[0] = 0;
+
+ if(accStep31)
+ {
+ rLen = 8;
+ memset(rdBuf, 0, sizeof(rdBuf));
if(twoByteMode[cpuid][rank])
{
- wrBuf[0] = static_cast<uint8_t>(curOut[i] & 0xFF);
- wrBuf[1] = static_cast<uint8_t>((curOut[i] >> 8) & 0xFF);
+ wrBuf[0] = static_cast<uint8_t>(curOut[0] & 0xFF);
+ wrBuf[1] = static_cast<uint8_t>((curOut[0] >> 8) & 0xFF);
wLen = 2;
}
else
{
- wrBuf[0] = static_cast<uint8_t>(curOut[i]);
- wLen = 1;
+ if constexpr (debug)
+ {
+ std::cout << "twoByteMode[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)twoByteMode[cpuid][rank] << std::endl;
+ }
+ if(pmicType[cpuid][rank] == PMIC5030)
+ {
+ return -1;
+ }
+ else
+ {
+ for(int i=0; i<6; i++)
+ {
+ dimmData.current[i] = calStep31CurPower(i, temp);
+ }
+ }
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
@@ -805,24 +930,43 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
{
return -1;
}
-
- if(accStep31)
- {
- temp[i] = rdBuf[0];
- }
- else
- {
- dimmData.current[i] = rdBuf[0] * 125.0 / 1000.0;
- }
- }
-
- if(accStep31)
- {
+ for(int i=0; i<index; i++) {
+ temp[i] = rdBuf[i];
+ }
+
for(int i=0; i<6; i++)
{
dimmData.current[i] = calStep31CurPower(i, temp);
}
}
+ else
+ {
+ for(int i=0; i<index; i++) {
+ rLen = 1;
+ rdBuf[0] = 0;
+ if(twoByteMode[cpuid][rank])
+ {
+ wrBuf[0] = static_cast<uint8_t>(curOut[i] & 0xFF);
+ wrBuf[1] = static_cast<uint8_t>((curOut[i] >> 8) & 0xFF);
+ wLen = 2;
+ }
+ else
+ {
+ wrBuf[0] = static_cast<uint8_t>(curOut[i]);
+ wLen = 1;
+ }
+
+ ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
+ if (ret < 0)
+ {
+ return -1;
+ }
+
+ dimmData.current[i] = rdBuf[0] * 125.0 / 1000.0;
+
+ }
+ }
+
//start to read power
if(twoByteMode[cpuid][rank])
@@ -835,7 +979,7 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
adcSelect[1] |= 0x40;
wLen = 2;
}
-
+ rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
if (ret < 0)
{
@@ -844,19 +988,34 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
- for(int i=0; i<index; i++) {
- rLen = 1;
- rdBuf[0] = 0;
+ // For Renesas requirements, I3C command: Continuously read R100~R107
+ if(accStep31)
+ {
+ rLen = 8;
+ memset(rdBuf, 0, sizeof(rdBuf));
if(twoByteMode[cpuid][rank])
{
- wrBuf[0] = static_cast<uint8_t>(curOut[i] & 0xFF);
- wrBuf[1] = static_cast<uint8_t>((curOut[i] >> 8) & 0xFF);
+ wrBuf[0] = static_cast<uint8_t>(curOut[0] & 0xFF);
+ wrBuf[1] = static_cast<uint8_t>((curOut[0] >> 8) & 0xFF);
wLen = 2;
}
else
{
- wrBuf[0] = static_cast<uint8_t>(curOut[i]);
- wLen = 1;
+ if constexpr (debug)
+ {
+ std::cout << "twoByteMode[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)twoByteMode[cpuid][rank] << std::endl;
+ }
+ if(pmicType[cpuid][rank] == PMIC5030)
+ {
+ return -1;
+ }
+ else
+ {
+ for(int i=0; i<6; i++)
+ {
+ dimmData.current[i] = calStep31CurPower(i, temp);
+ }
+ }
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
@@ -864,24 +1023,42 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
{
return -1;
}
-
- if(accStep31)
- {
- temp[i] = rdBuf[0];
- }
- else
- {
- dimmData.power[i] = rdBuf[0] * 125.0 / 1000.0;
- }
- }
-
- if(accStep31)
- {
- for(int i=0; i<STATUS_PMIC_RAIL_NUM; i++)
+ for(int i=0; i<index; i++) {
+ temp[i] = rdBuf[i];
+ }
+
+ for(int i=0; i<6; i++)
{
dimmData.power[i] = calStep31CurPower(i, temp);
}
}
+ else
+ {
+ for(int i=0; i<index; i++)
+ {
+ rLen = 1;
+ rdBuf[0] = 0;
+ if(twoByteMode[cpuid][rank])
+ {
+ wrBuf[0] = static_cast<uint8_t>(curOut[i] & 0xFF);
+ wrBuf[1] = static_cast<uint8_t>((curOut[i] >> 8) & 0xFF);
+ wLen = 2;
+ }
+ else
+ {
+ wrBuf[0] = static_cast<uint8_t>(curOut[i]);
+ wLen = 1;
+ }
+
+ ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
+ if (ret < 0)
+ {
+ return -1;
+ }
+ dimmData.power[i] = rdBuf[0] * 125.0 / 1000.0;
+
+ }
+ }
return 0;
}
@@ -994,7 +1171,7 @@ void DIMMSpdReader::readDimmInfo()
}
}
updateField(dimmName, TEMP, dData.temp, STATUS_TEMP_NUM);
-#if 0
+#if 1
if(regCounter == 0)
{
ret = getPmicStatusRegs(cpuid, i, dData);
--
2.34.1
@@ -218,7 +218,13 @@ void updateField(const std::string& dimmName, FieldType field, T newValues[], si
std::cout << "Invalid size for status array!" << std::endl;
}
break;
case ERROR:
if (size == STATUS_ERROR_NUM) {
std::copy(newValues, newValues + size, std::begin(it->second.error));
} else {
std::cout << "Invalid size for error array!" << std::endl;
}
break;
default:
std::cout << "Unknown field type!" << std::endl;
break;
@@ -456,10 +462,10 @@ int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
uint8_t index[] = {0xc8, 0xcc, 0xd0};
uint16_t wLen = 2;
//Jim debug uint8_t wrBuf[] = {0, 0};
uint8_t wrBuf[] = {0, 0, 0}; //Jim debug
uint8_t wrBuf[] = {0, 0, 0};
uint8_t rdBuf[] = {0};
uint16_t rLen = 1;
uint8_t typeVal = 0;
int spd = NUM_TO_SPD(rank);
const uint8_t memReg = 0x80;
@@ -485,9 +491,13 @@ int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
return -1;
}
if((rdBuf[0] & 0xf) == 0x6)
//SPD 0xc8, 0xcc, 0xd0 is Device Types
//Check DeviceType[7] = 1 is Installed
if((rdBuf[0] & 0x80) != 0)
{
pmicType[cpuid][rank] = PMIC5030;
//read DeviceType Bits[3:0]
typeVal = rdBuf[0] & 0xf;
pmicType[cpuid][rank] = (typeVal <= PMIC5030) ? static_cast<PMICType>(typeVal) : Unknown;
break;
}
}
@@ -499,8 +509,6 @@ int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
gotType[cpuid][rank] = true;
//Jim debug+S
//----------------------------------------------------------------------------
//A. 1B Write R30 = 0x84 // 1 byte format, set 2 byte mode
//B. 2B Read R0030 //check 2 byte mode
@@ -593,7 +601,8 @@ int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
}
}
//Jim debug+E
if constexpr (debug)
{
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
@@ -736,10 +745,10 @@ int DIMMSpdReader::getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmDat
int index = (pmicType[cpuid][rank] == PMIC5030) ? 6 : 4;
for(int i=0; i<index; i++) {
//Write R30
rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
rLen = 0; //For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
if(twoByteMode[cpuid][rank])
{
adcValue = 0x4; //Jim debug, PMIC5030 fixed the 2 byte mode + 1ms
adcValue = 0x4; //PMIC5030 fixed the 2 byte mode + 1ms
wrBuf[2] = adcValue | adcSel[i];
wLen = 3;
}
@@ -754,14 +763,12 @@ int DIMMSpdReader::getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmDat
{
return -1;
}
//Jim debug std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
//Jim debug+S
// For Renesas requirements, the JESD spec PMIC5030 needs a 9ms delay.
if(pmicType[cpuid][rank] == PMIC5030)
std::this_thread::sleep_for(std::chrono::milliseconds(9));
else
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
//Jim debug+E
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
rLen = 1;
@@ -808,6 +815,147 @@ static double calStep31CurPower(int index, const uint8_t (&temp)[8])
return result;
}
int DIMMSpdReader::checkADCAccuracyStepSize(uint8_t cpuid, uint8_t rank, DimmData& dimmData, const uint8_t* TargetData)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
if constexpr (debug)
{
std::cout << "Start to check ADC Accuracy Step Size."<< std::endl;
}
uint16_t wLen;
uint16_t rLen;
uint8_t rdBuf[] = {0};
uint8_t wrBuf[3] = {0, 0, 0};
uint16_t ThresholdSel[6] = {0x1C, 0x1D, 0x1E, 0x1F, 0x11A, 0x11B}; //OUTPUT_HIGH_CURRENT_CONSUMPTION_WARNING_THRESHOLD
int pmic = NUM_TO_PMIC(rank);
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
// 1. Read R32
rLen = 1;
wLen = 2;
wrBuf[0] = 0x32; //address_Low
wrBuf[1] = 0; //address_High
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
if((rdBuf[0] & 0x3) != 1)
{
dimmData.error[0] |= 1;
}
// 2. Read ThresholdSel {0x1C, 0x1D, 0x1E, 0x1F, 0x11A, 0x11B}
rLen = 1;
wLen = 2;
for(int i=0; i<6; i++) {
wrBuf[0] = static_cast<uint8_t>(ThresholdSel[i] & 0xFF); //address_Low
wrBuf[1] = static_cast<uint8_t>((ThresholdSel[i]>>8) & 0xFF); //address_High
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
if(rdBuf[0] != TargetData[i])
{
dimmData.error[0] |= 1<<(i+1);
}
}
return ret;
}
int DIMMSpdReader::setADCAccuracyStepSize(uint8_t cpuid, uint8_t rank, DimmData& dimmData, uint8_t R32)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
if constexpr (debug)
{
std::cout << "Start to set Pmic5030 ADC Accuracy Step Size."<< std::endl;
}
uint16_t wLen;
uint16_t rLen;
uint8_t rdBuf[] = {0};
uint8_t wrBuf[3] = {0, 0, 0};
uint16_t ThresholdSel[6] = {0x1C, 0x1D, 0x1E, 0x1F, 0x11A, 0x11B}; //OUTPUT_HIGH_CURRENT_CONSUMPTION_WARNING_THRESHOLD
uint8_t ThresholdData[6] = {0, 0, 0, 0, 0, 0};
uint8_t TargetData[6] = {0, 0, 0, 0, 0, 0};
uint8_t adcAcc[] = {0x32, 0, 0};
uint32_t calcData = 0;
constexpr int PMIC_CHANNEL_SWD_INDEX = 3;
constexpr uint8_t PMIC_MAX_CUR_7500MA_REG_VAL = 0xF0; // SWA, SWB, SWC, SWE, SWF
constexpr uint8_t PMIC_MAX_CUR_5000MA_REG_VAL = 0xA0; // SWD
int pmic = NUM_TO_PMIC(rank);
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
// 1. Read ThresholdSel {0x1C, 0x1D, 0x1E, 0x1F, 0x11A, 0x11B}
rLen = 1;
wLen = 2;
for(int i=0; i<6; i++) {
wrBuf[0] = static_cast<uint8_t>(ThresholdSel[i] & 0xFF); //address_Low
wrBuf[1] = static_cast<uint8_t>((ThresholdSel[i]>>8) & 0xFF); //address_High
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, &ThresholdData[i], rLen);
if (ret < 0)
{
return -1;
}
}
// 2. Write R32[1:0] = 01b
adcAcc[2] = (R32&0xFC)|0x1;
wLen = 3;
rLen = 0;
ret = i3cWriteRead(i3cPmicName, adcAcc, wLen, rdBuf, rLen);
if (ret < 0)
{
//std::cerr << " read word data failed. \n";
return -1;
}
// 3. Write ThresholdData
for(int i=0; i<6; i++) {
rLen = 0;
wLen = 3;
wrBuf[0] = static_cast<uint8_t>(ThresholdSel[i] & 0xFF); //address_Low
wrBuf[1] = static_cast<uint8_t>((ThresholdSel[i]>>8) & 0xFF); //address_High
//data
calcData = (ThresholdData[i] * 4); // 125/31.25 = 4
if (i == PMIC_CHANNEL_SWD_INDEX) {
// SWD Maximum current is 5000mA
TargetData[i] = (calcData > PMIC_MAX_CUR_5000MA_REG_VAL) ? PMIC_MAX_CUR_5000MA_REG_VAL : static_cast<uint8_t>(calcData);
}
else {
// SWA, SWB, SWC, SWE, SWF Maximum current is 7500mA
TargetData[i] = (calcData > PMIC_MAX_CUR_7500MA_REG_VAL) ? PMIC_MAX_CUR_7500MA_REG_VAL : static_cast<uint8_t>(calcData);
}
wrBuf[2] = TargetData[i];
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
}
ret = checkADCAccuracyStepSize(cpuid, rank, dimmData, TargetData);
if (ret < 0)
{
//std::cerr << " set ADCAccuracy Step Size failed. \n";
return -1;
}
return ret;
}
int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
{
@@ -828,8 +976,7 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
uint8_t adcSelect[] = {0x1b, 0, 0};
uint16_t curOut[8];
uint8_t temp[8];
uint8_t rdBuf[] = {0, 0, 0, 0, 0, 0, 0, 0}; //Jim debug, For Renesas requirements, I3C command: Continuously read R100~R107
//Jim debug uint8_t rdBuf[] = {0};
uint8_t rdBuf[] = {0, 0, 0, 0, 0, 0, 0, 0}; //For Renesas requirements, I3C command: Continuously read R100~R107
uint8_t wrBuf[] = {0, 0};
int pmic = NUM_TO_PMIC(rank);
@@ -846,6 +993,20 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
return -1;
}
if((rdBuf[0] & 0x3) == 1) accStep31 = true;
else
{
if(twoByteMode[cpuid][rank])
{
//if two Byte Mode + PMIC5030, R32[1:0] set 01b
ret = setADCAccuracyStepSize(cpuid, rank, dimmData, rdBuf[0]);
accStep31 = true;
if (ret < 0)
{
//std::cerr << " set ADCAccuracy Step Size failed. \n";
return -1;
}
}
}
if constexpr (debug)
{
std::cout << "accStep31: " << (int)accStep31 << std::endl;
@@ -886,7 +1047,7 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
adcSelect[1] = rdBuf[0] & 0xbf; //Read current
wLen = 2;
}
rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
rLen = 0; //For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
if (ret < 0)
{
@@ -916,13 +1077,6 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
{
return -1;
}
else
{
for(int i=0; i<6; i++)
{
dimmData.current[i] = calStep31CurPower(i, temp);
}
}
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
@@ -979,7 +1133,7 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
adcSelect[1] |= 0x40;
wLen = 2;
}
rLen = 0; //Jim debug, For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
rLen = 0; //For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
if (ret < 0)
{
@@ -1009,13 +1163,6 @@ int DIMMSpdReader::getDIMMRegsCurAndPow(uint8_t cpuid, uint8_t rank, DimmData& d
{
return -1;
}
else
{
for(int i=0; i<6; i++)
{
dimmData.current[i] = calStep31CurPower(i, temp);
}
}
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
@@ -1097,6 +1244,7 @@ void DIMMSpdReader::init()
for(int i=0; i<MAX_DIMM_RANK; i++) {
DimmData dData = {
{0, 0, 0, 0, 0, 0, 0, 0},
{0},
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
@@ -1113,7 +1261,7 @@ void DIMMSpdReader::init()
dimmDataTable.insert_or_assign(dimmName, std::move(dData));
pmicType[cpuid][i] = PMIC5010;
pmicType[cpuid][i] = Unknown;
gotType[cpuid][i] = false;
twoByteMode[cpuid][i] = false;
}
@@ -1131,21 +1279,19 @@ void DIMMSpdReader::readDimmInfo()
for(int cpuid=0; cpuid<MAX_CPU_ID; cpuid++) {
for(int i=0; i<MAX_DIMM_RANK; i++) {
DimmData dData = {
{0, 0, 0, 0, 0, 0, 0, 0},
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()},
{std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN()}};
std::string dimmName = "DIMM_CPU" + std::string(1, '0' + cpuid) + "_" + std::string(1, 'A' + i);
DimmData dData = dimmDataTable[dimmName];
for (int j = 0; j < STATUS_TEMP_NUM; j++) {
dData.temp[j] = std::numeric_limits<double>::quiet_NaN();
}
for (int j = 0; j < STATUS_PMIC_RAIL_NUM; j++) {
dData.voltage[j] = std::numeric_limits<double>::quiet_NaN();
dData.current[j] = std::numeric_limits<double>::quiet_NaN();
dData.power[j] = std::numeric_limits<double>::quiet_NaN();
}
for (int j = 0; j < STATUS_REG_NUM; j++) {
dData.reg[j] = 0;
}
int index = cpuid * 4 + i / 3;
if(index != lastIndex) {
@@ -1211,6 +1357,7 @@ void DIMMSpdReader::readDimmInfo()
updateField(dimmName, CURRENT, dData.current, STATUS_PMIC_RAIL_NUM);
updateField(dimmName, POWER, dData.power, STATUS_PMIC_RAIL_NUM);
updateField(dimmName, ERROR, dData.error, STATUS_ERROR_NUM);
}
#endif
}
@@ -1266,6 +1413,11 @@ void DIMMSpdReader::updateDbus()
dimm_statusReg_inf[data.first]->set_property("0x0a", data.second.reg[6]);
dimm_statusReg_inf[data.first]->set_property("0x0b", data.second.reg[7]);
}
if(dimm_errCode_inf.find(data.first) != dimm_errCode_inf.end()) {
dimm_errCode_inf[data.first]->set_property("0x32", data.second.error[0]);
}
}
}
@@ -1320,6 +1472,9 @@ void DIMMSpdReader::updateToDimmInfoFile()
js[data.first]["Status_Reg"]["0x09"] = data.second.reg[5];
js[data.first]["Status_Reg"]["0x0a"] = data.second.reg[6];
js[data.first]["Status_Reg"]["0x0b"] = data.second.reg[7];
//update error code
js[data.first]["Error_Code"]["0x32"] = data.second.error[0];
}
jsonOutputFile << js.dump(4);
@@ -16,28 +16,33 @@
#define STATUS_TEMP_NUM 3
#define STATUS_PMIC_RAIL_NUM 6
#define STATUS_REG_NUM 8
#define STATUS_ERROR_NUM 1
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_temp_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_voltage_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_current_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_power_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_statusReg_inf;
extern std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_errCode_inf;
enum FieldType {
VOLTAGE,
CURRENT,
POWER,
TEMP,
STATUS
STATUS,
ERROR
};
struct DimmData
{
uint8_t reg[STATUS_REG_NUM];
uint8_t error[STATUS_ERROR_NUM];
double voltage[STATUS_PMIC_RAIL_NUM];
double current[STATUS_PMIC_RAIL_NUM];
double power[STATUS_PMIC_RAIL_NUM];
double temp[STATUS_TEMP_NUM];
};
struct DimmI3CAddr
@@ -53,7 +58,8 @@ enum PMICType {
PMIC5020,
PMIC5120,
PMIC5200,
PMIC5030
PMIC5030,
Unknown = 0xFF
};
struct DIMMSpdReader : std::enable_shared_from_this<DIMMSpdReader>
@@ -81,6 +87,8 @@ struct DIMMSpdReader : std::enable_shared_from_this<DIMMSpdReader>
void getdimmI3cSwitchState(const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t retries = 2);
int getPmicType(uint8_t cpuid, uint8_t rank);
int getPmicStatusRegs(uint8_t cpuid, uint8_t rank, DimmData& dimmData);
int setADCAccuracyStepSize(uint8_t cpuid, uint8_t rank, DimmData& dimmData, uint8_t R32);
int checkADCAccuracyStepSize(uint8_t cpuid, uint8_t rank, DimmData& dimmData, const uint8_t* ThresholdData);
private:
std::vector<sdbusplus::bus::match_t> matches;
@@ -59,6 +59,8 @@ std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>
std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_current_inf;
std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_power_inf;
std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_statusReg_inf;
std::unordered_map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>> dimm_errCode_inf;
int main()
{
@@ -177,6 +179,13 @@ int main()
dimm_statusReg_inf[dimm]->register_property(
"0x0b", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
dimm_statusReg_inf[dimm]->initialize();
dimm_errCode_inf[dimm] = objectServer.add_interface(interfacePath,
"xyz.openbmc_project.Dimm.ErrCode");
dimm_errCode_inf[dimm]->register_property(
"0x32", uint8_t(0), sdbusplus::asio::PropertyPermission::readWrite);
dimm_errCode_inf[dimm]->initialize();
}
double pollRate = 0.1;
@@ -1374,7 +1374,7 @@ ipmi::RspType<uint8_t> ipmiBiosSetDimmPara(ipmi::Context::ptr ctx, std::vector<u
railData[3] = static_cast<double>(dimmInfo.dimmCur.SWD) / 1000.0;
railData[4] = static_cast<double>(dimmInfo.dimmCur.SWE) / 1000.0;
railData[5] = static_cast<double>(dimmInfo.dimmCur.SWF) / 1000.0;
for(int i=0; i<4; i++) {
for(int i=0; i<6; i++) { //Jim debug check i<6 or i<4
ret = setDimmParaToDbus(ctx, dimmName, "Current", railName[i], railData[i]);
if(ret < 0)
return ipmi::responseUnspecifiedError();
@@ -1387,7 +1387,7 @@ ipmi::RspType<uint8_t> ipmiBiosSetDimmPara(ipmi::Context::ptr ctx, std::vector<u
railData[3] = static_cast<double>(dimmInfo.dimmPow.SWD) / 1000.0;
railData[4] = static_cast<double>(dimmInfo.dimmPow.SWE) / 1000.0;
railData[5] = static_cast<double>(dimmInfo.dimmPow.SWF) / 1000.0;
for(int i=0; i<4; i++) {
for(int i=0; i<6; i++) { //Jim debug check i<6 or i<4
ret = setDimmParaToDbus(ctx, dimmName, "Power", railName[i], railData[i]);
if(ret < 0)
return ipmi::responseUnspecifiedError();
@@ -1740,6 +1740,21 @@ static std::optional<T> getDIMMData(const nlohmann::json& js, const std::string&
auto value = dimmData["Status_Reg"][regStr];
return static_cast<T>(value.get<int>());
}
else if (dataType == DataType::ERROR) {
auto err = static_cast<ErrCode>(indexId);
std::string errStr;
char hexStr[5];
snprintf(hexStr, sizeof(hexStr), "0x%02x", static_cast<int>(err));
errStr = hexStr;
if (!dimmData["Error_Code"].contains(errStr)) {
return std::nullopt;
}
auto value = dimmData["Error_Code"][errStr];
return static_cast<T>(value.get<int>());
}
} catch (std::exception& e) {
return std::nullopt;
}
@@ -1748,7 +1763,7 @@ static std::optional<T> getDIMMData(const nlohmann::json& js, const std::string&
}
/****************************************************************************
reqId: 0:TS0 1:TS1 2:SPD_TEMP 3: Max Temp 4:Voltage 5:Current 6: Status Reg
reqId: 0:TS0 1:TS1 2:SPD_TEMP 3: Max Temp 4:Voltage 5:Current 6: Status Reg 7: Error Code
*****************************************************************************/
ipmi::RspType<std::vector<uint8_t>> ipmiGetDimmTemp(uint8_t reqId)
{
@@ -1757,7 +1772,7 @@ ipmi::RspType<std::vector<uint8_t>> ipmiGetDimmTemp(uint8_t reqId)
const nlohmann::json empty{};
nlohmann::json js;
if(reqId > 6) {
if(reqId > 7) {
std::cout << "invalid reqId :" << (int)reqId << std::endl;
return ipmi::responseParmOutOfRange();
}
@@ -1806,6 +1821,7 @@ ipmi::RspType<std::vector<uint8_t>> ipmiGetDimmTemp(uint8_t reqId)
+ "_" + std::string(1, 'A' + i);
std::optional<double> temp, swa, swb, swc, swd, swe, swf;
std::optional<uint8_t> r4, r5, r6, r7, r8, r9, ra, rb;
std::optional<uint8_t> err_r32;
switch(static_cast<ReqId>(reqId))
{
@@ -1847,6 +1863,11 @@ ipmi::RspType<std::vector<uint8_t>> ipmiGetDimmTemp(uint8_t reqId)
ra = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_0A);
rb = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_0B);
break;
case ReqId::ERROR_CODE:
err_r32 = getDIMMData<uint8_t>(js, dimmName, DataType::ERROR, ErrCode::errCode_REG_32);
break;
default:
std::cout << "invalid reqId :" << (int)reqId << std::endl;
return ipmi::responseParmOutOfRange();
@@ -1865,6 +1886,11 @@ ipmi::RspType<std::vector<uint8_t>> ipmiGetDimmTemp(uint8_t reqId)
byte_vector.push_back(opt.value_or(0xFF));
}
}
else if(reqId == 7) {
for (const auto& opt : {err_r32}) {
byte_vector.push_back(opt.value_or(0xFF));
}
}
else {
for (const auto& rail : {swa, swb, swc, swd, swe, swf}) {
auto bytes = convertDoubleToTwoBytes(rail);
@@ -20,7 +20,8 @@ enum class DataType {
CURRENT,
POWER,
VOLTAGE,
STATUS
STATUS,
ERROR
};
enum class TempSensor {
@@ -37,7 +38,8 @@ enum class ReqId {
MAX_TEMP = 3,
VOLTAGE = 4,
CURRENT = 5,
STATUS_REG = 6
STATUS_REG = 6,
ERROR_CODE = 7
};
enum class RailChannel {
@@ -60,6 +62,10 @@ enum class StatusReg {
REG_0B = 0x0B
};
enum class ErrCode {
errCode_REG_32 = 0x32
};
typedef struct {
int8_t int_part;
uint8_t frac_part;