Files
OpenBMC/meta-luxshare/meta-bhs/recipes-phosphor/dimm/dimm-spd-reader/dimmSpdReader.cpp
T
Your Name 0cc0c96893 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.
2026-04-27 10:01:06 +08:00

1521 lines
46 KiB
C++
Executable File

/*
// Copyright (c) 2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include "dimmSpdReader.hpp"
#include "i3cdev.h"
#include <gpiod.hpp>
#include <phosphor-logging/lg2.hpp>
#include <stdint.h>
#include <chrono>
#include <cmath>
#include <functional>
#include <limits>
#include <memory>
#include <numeric>
#include <string>
#include <vector>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <nlohmann/json.hpp>
static constexpr bool debug = false;
#define PECI_MBX_INDEX_DDR_DIMM_TEMP 0x0E
constexpr auto dimmSensorInterface = "xyz.openbmc_project.Sensor.dimmLED";
constexpr auto dimmSensorPath = "/xyz/openbmc_project/sensors/temperature/";
constexpr auto HostMiscDbusName = "xyz.openbmc_project.Host.Misc.Manager";
constexpr auto platformStatePath = "/xyz/openbmc_project/misc/platform_state";
constexpr auto platformStateInterface = "xyz.openbmc_project.State.Host.Misc";
constexpr auto postCompleteProperty = "PostComplete";
static constexpr const char* dimmInfoPath = "/var/log/dimmInfo.json";
static constexpr const char* dimmInfoTempPath = "/usr/share/dimm-spd-reader/dimmInfo_template.json";
static int lastIndex = -1;
#define NUM_TO_SPD(n) (((n) % 3) * 2)
#define NUM_TO_PMIC(n) (((n) % 3) * 2 + 8)
#define I3C_ADDR(cpuid) ("/dev/i3c-" + std::to_string(cpuid) + "-3c00000000")
#define I3C_TS0_ADDR(cpuid) ("/dev/i3c-" + std::to_string(cpuid) + "-3c00000001")
#define I3C_TS1_ADDR(cpuid) ("/dev/i3c-" + std::to_string(cpuid) + "-3c00000003")
static boost::container::flat_map<std::string, DimmData> dimmDataTable;
const boost::container::flat_map<std::string, bool> cfgCpu0DimmABC = {
{"I3C_SPD_BMC_MUX0_SEL", false},
{"I3C_SPD_BMC_MUX0_EN", false},
{"I3C_SPD_BMC_MUX1_SEL", true},
{"I3C_SPD_BMC_MUX1_EN", true}};
const boost::container::flat_map<std::string, bool> cfgCpu0DimmDEF = {
{"I3C_SPD_BMC_MUX0_SEL", true},
{"I3C_SPD_BMC_MUX0_EN", false},
{"I3C_SPD_BMC_MUX1_SEL", true},
{"I3C_SPD_BMC_MUX1_EN", true}};
const boost::container::flat_map<std::string, bool> cfgCpu0DimmGHI = {
{"I3C_SPD_BMC_MUX0_SEL", true},
{"I3C_SPD_BMC_MUX0_EN", true},
{"I3C_SPD_BMC_MUX1_SEL", false},
{"I3C_SPD_BMC_MUX1_EN", false}};
const boost::container::flat_map<std::string, bool> cfgCpu0DimmJKL = {
{"I3C_SPD_BMC_MUX0_SEL", true},
{"I3C_SPD_BMC_MUX0_EN", true},
{"I3C_SPD_BMC_MUX1_SEL", true},
{"I3C_SPD_BMC_MUX1_EN", false}};
const boost::container::flat_map<std::string, bool> cfgCpu1DimmABC = {
{"I3C_SPD_BMC_MUX2_SEL", false},
{"I3C_SPD_BMC_MUX2_EN", false},
{"I3C_SPD_BMC_MUX3_SEL", true},
{"I3C_SPD_BMC_MUX3_EN", true}};
const boost::container::flat_map<std::string, bool> cfgCpu1DimmDEF = {
{"I3C_SPD_BMC_MUX2_SEL", true},
{"I3C_SPD_BMC_MUX2_EN", false},
{"I3C_SPD_BMC_MUX3_SEL", true},
{"I3C_SPD_BMC_MUX3_EN", true}};
const boost::container::flat_map<std::string, bool> cfgCpu1DimmGHI = {
{"I3C_SPD_BMC_MUX2_SEL", true},
{"I3C_SPD_BMC_MUX2_EN", true},
{"I3C_SPD_BMC_MUX3_SEL", false},
{"I3C_SPD_BMC_MUX3_EN", false}};
const boost::container::flat_map<std::string, bool> cfgCpu1DimmJKL = {
{"I3C_SPD_BMC_MUX2_SEL", true},
{"I3C_SPD_BMC_MUX2_EN", true},
{"I3C_SPD_BMC_MUX3_SEL", true},
{"I3C_SPD_BMC_MUX3_EN", false}};
static std::vector<boost::container::flat_map<std::string, bool>> cfgGPIO = {
cfgCpu0DimmABC,
cfgCpu0DimmDEF,
cfgCpu0DimmGHI,
cfgCpu0DimmJKL,
cfgCpu1DimmABC,
cfgCpu1DimmDEF,
cfgCpu1DimmGHI,
cfgCpu1DimmJKL
};
static inline std::string to_hex(int num) {
std::stringstream ss;
ss << std::hex << num;
return ss.str();
}
static inline std::string get_current_timestamp() {
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
std::tm tm = *std::localtime(&now_time);
std::stringstream ss;
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); // 格式化为 "YYYY-MM-DD HH:MM:SS"
return ss.str();
}
static bool getDbusMsgState(sdbusplus::message_t& msg, bool& value)
{
std::string pltStateInterface;
std::string event;
boost::container::flat_map<std::string, std::variant<bool>>
propertiesChanged;
try
{
msg.read(pltStateInterface, propertiesChanged);
if (propertiesChanged.empty())
{
return false;
}
std::string property = propertiesChanged.begin()->first;
if (property.empty() || property != "dimmI3cSwitch")
{
return false;
}
value = std::get<bool>(propertiesChanged.begin()->second);
return true;
}
catch (const std::exception& e)
{
std::cerr << "exception while reading dbus property dimmI3cSwitch" << "\n";
return false;
}
}
static int getADCUpdateTime(int value) {
static const int updateTimes[] = {1, 2, 4, 8};
if (value >= 0 && value < 4) {
return updateTimes[value];
} else {
return 8;
}
}
template <typename T>
void updateField(const std::string& dimmName, FieldType field, T newValues[], size_t size) {
auto it = dimmDataTable.find(dimmName);
if (it != dimmDataTable.end()) {
switch (field) {
case VOLTAGE:
if (size == STATUS_PMIC_RAIL_NUM) {
std::copy(newValues, newValues + size, std::begin(it->second.voltage));
} else {
std::cout << "Invalid size for voltage array!" << std::endl;
}
break;
case CURRENT:
if (size == STATUS_PMIC_RAIL_NUM) {
std::copy(newValues, newValues + size, std::begin(it->second.current));
} else {
std::cout << "Invalid size for current array!" << std::endl;
}
break;
case POWER:
if (size == STATUS_PMIC_RAIL_NUM) {
std::copy(newValues, newValues + size, std::begin(it->second.power));
} else {
std::cout << "Invalid size for power array!" << std::endl;
}
break;
case TEMP:
if (size == STATUS_TEMP_NUM) {
std::copy(newValues, newValues + size, std::begin(it->second.temp));
} else {
std::cout << "Invalid size for temp array!" << std::endl;
}
break;
case STATUS:
if (size == STATUS_REG_NUM) {
std::copy(newValues, newValues + size, std::begin(it->second.reg));
} else {
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;
}
} else {
std::cout << "DIMM not found!" << std::endl;
}
}
void DIMMSpdReader::getdimmI3cSwitchState(const std::shared_ptr<sdbusplus::asio::connection>& conn,
size_t retries)
{
conn->async_method_call(
[conn, retries, this](boost::system::error_code ec,
const std::variant<bool>& state) {
if (ec)
{
if (retries != 0U)
{
auto timer = std::make_shared<boost::asio::steady_timer>(
conn->get_io_context());
timer->expires_after(std::chrono::seconds(15));
timer->async_wait(
[timer, conn, retries, this](boost::system::error_code) {
this->getdimmI3cSwitchState(conn, retries - 1);
});
return;
}
std::cerr << "error getting dimm I3cSwitchState" << ec.message() << "\n";
return;
}
bool i3cSwitchState = std::get<bool>(state);
std::cout << "i3cSwitch state: " << (int)i3cSwitchState << std::endl;
if(i3cSwitchState)
{
int ret = system("modprobe dw-i3c-master");
if (ret != 0) {
std::cout << "Failed to modprobe dw-i3c-master module" << std::endl;
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Start dimm spd reader" << std::endl;
this->startRead();
}
},
HostMiscDbusName, platformStatePath, "org.freedesktop.DBus.Properties", "Get",
platformStateInterface, "dimmI3cSwitch");
}
void DIMMSpdReader::dimmI3cSwitchMatcher(
std::vector<sdbusplus::bus::match_t>& matches, sdbusplus::bus_t& connection,
std::function<void(bool)>&& onMatch)
{
auto pulseEventMatcherCallback =
[onMatch{std::move(onMatch)}, this](sdbusplus::message_t& msg) {
bool value = false;
if (!getDbusMsgState(msg, value))
{
return;
}
onMatch(value);
};
matches.emplace_back(
connection,
"type='signal',interface='org.freedesktop.DBus.Properties',member='"
"PropertiesChanged',arg0='" +
std::string(platformStateInterface) + "'",
std::move(pulseEventMatcherCallback));
}
static bool setGPIOOutput(const std::string& name, const int value,
gpiod::line& gpioLine)
{
// Find the GPIO line
gpioLine = gpiod::find_line(name);
if (!gpioLine)
{
lg2::error("Failed to find the {GPIO_NAME} line", "GPIO_NAME", name);
return false;
}
// Request GPIO output to specified value
try
{
gpioLine.request({"dimm-spd-reader", gpiod::line_request::DIRECTION_OUTPUT, {}},
value);
}
catch (const std::exception& e)
{
lg2::error("Failed to request {GPIO_NAME} output: {ERROR}", "GPIO_NAME",
name, "ERROR", e);
return false;
}
lg2::debug("{GPIO_NAME} set to {GPIO_VALUE}", "GPIO_NAME", name,
"GPIO_VALUE", value);
return true;
}
static void setGPIOToSelectDimm(const boost::container::flat_map<std::string, bool>& cfgMap)
{
for(auto cfg : cfgMap)
{
gpiod::line line;
if (!setGPIOOutput(cfg.first, (int)cfg.second, line))
{
std::cerr << "Setting I3CSwitch GPIO failed \n";
return;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
static int i3cWriteRead(std::string& i3cDev, uint8_t wBuf[], uint16_t wLen,
uint8_t rBuf[], uint16_t rLen)
{
struct i3c_ioc_priv_xfer xfers[2];
int nxfers = 0;
if constexpr (debug)
{
std::cout << "i3c data to write:" << std::endl;
for(int i=0; i<wLen; i++)
{
std::cout << "wBuf[" << i << "]: 0x" << std::hex << (int)wBuf[i] << std::dec << " ";
}
std::cout << std::endl;
}
int fd = open(i3cDev.c_str(), O_RDWR);
if (fd < 0)
{
std::cerr << " unable to open i3c device " << i3cDev << "\n";
goto err;
}
memset(xfers, 0, sizeof(xfers));
if (wLen)
{
xfers[nxfers].len = wLen;
xfers[nxfers].rnw = 0;
xfers[nxfers].data = (uintptr_t)wBuf;
nxfers++;
}
if (rLen)
{
xfers[nxfers].len = rLen;
xfers[nxfers].rnw = 1;
xfers[nxfers].data = (uintptr_t)rBuf;
nxfers++;
}
if (ioctl(fd, I3C_IOC_PRIV_XFER(nxfers), xfers) < 0) {
if constexpr (debug)
{
std::cerr << "i3c transfer failed "<< "\n";
}
goto err;
}
for (int i = 0; i < nxfers; i++) {
if (xfers[i].rnw) {
memcpy((void *)rBuf, (void *)(uintptr_t)xfers[i].data, xfers[i].len * sizeof(uint8_t));
}
}
if constexpr (debug)
{
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);
return 0;
err:
close(fd);
return -1;
}
void DIMMSpdReader::startRead()
{
waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
waitTimer.async_wait([this](const boost::system::error_code& ec) {
if (ec == boost::asio::error::operation_aborted)
{
return; // we're being cancelled
}
// read timer error
if (ec)
{
std::cerr << "timer error\n";
return;
}
readDimmInfo();
updateDbus();
updateToDimmInfoFile();
if(regCounter == 0)
{
regCounter = 6000; //read status registers per 10 minutes.
}
else
{
regCounter--;
}
if(pmicCounter == 0)
{
pmicCounter = 300; //read status registers per 30s.
}
else
{
pmicCounter--;
}
startRead();
});
}
int DIMMSpdReader::getPmicType(uint8_t cpuid, uint8_t rank)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
if(gotType[cpuid][rank]) return 0;
uint8_t index[] = {0xc8, 0xcc, 0xd0};
uint16_t wLen = 2;
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;
std::string i3cSpdName = I3C_ADDR(cpuid) + to_hex(spd);
wrBuf[0] = 0xb;
ret = i3cWriteRead(i3cSpdName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
size_t size = sizeof(index) / sizeof(index[0]);
for(size_t i = 0; i < size; i++)
{
wrBuf[0] = static_cast<uint8_t>(memReg | (index[i] & 0x40) | (index[i] & 0x3F));
wrBuf[1] = static_cast<uint8_t>((index[i] >> 7) & 0x0F);
ret = i3cWriteRead(i3cSpdName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
//SPD 0xc8, 0xcc, 0xd0 is Device Types
//Check DeviceType[7] = 1 is Installed
if((rdBuf[0] & 0x80) != 0)
{
//read DeviceType Bits[3:0]
typeVal = rdBuf[0] & 0xf;
pmicType[cpuid][rank] = (typeVal <= PMIC5030) ? static_cast<PMICType>(typeVal) : Unknown;
break;
}
}
if(pmicType[cpuid][rank] == PMIC5030)
{
twoByteMode[cpuid][rank] = true;
}
gotType[cpuid][rank] = true;
//----------------------------------------------------------------------------
//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;
}
}
}
if constexpr (debug)
{
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
std::cout << "gotType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)gotType[cpuid][rank] << std::endl;
}
return ret;
}
int DIMMSpdReader::getDIMMRegsTemp(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
if constexpr (debug)
{
std::cout << "Start to get DIMM temperature "<< std::endl;
}
uint8_t wrBuf[] = {0x31};
uint16_t wLen = 1;
uint8_t rdBuf[] = {0, 0};
uint16_t rLen = 2;
uint16_t integerPart;
uint16_t fractionalPart;
int spd = NUM_TO_SPD(rank);
#if 0
std::string i3cSpdName = I3C_ADDR(cpuid) + to_hex(spd);
ret = i3cWriteRead(i3cSpdName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
integerPart = ((rdBuf[0] & 0xf0) >> 4) | ((rdBuf[1] & 0x0f) << 4);
fractionalPart = (rdBuf[0] & 0x0C) >> 2;
// check if a negative reading
if (rdBuf[1] & 0x10)
{
uint16_t tmp = (integerPart << 2) | fractionalPart;
tmp = ((~tmp) & 0x3ff) + 1;
fractionalPart = tmp & 0x3;
integerPart = tmp >> 2;
dimmData.temp[2] = -1.0 * (integerPart + fractionalPart * 0.25);
}
else
{
dimmData.temp[2] = integerPart + fractionalPart * 0.25;
}
#endif
std::string i3cTS0Name = I3C_TS0_ADDR(cpuid) + to_hex(spd);
memset(rdBuf, 0, sizeof(rdBuf));
ret = i3cWriteRead(i3cTS0Name, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
integerPart = ((rdBuf[0] & 0xf0) >> 4) | ((rdBuf[1] & 0x0f) << 4);
fractionalPart = (rdBuf[0] & 0x0C) >> 2;
// check if a negative reading
if (rdBuf[1] & 0x10)
{
uint16_t tmp = (integerPart << 2) | fractionalPart;
tmp = ((~tmp) & 0x3ff) + 1;
fractionalPart = tmp & 0x3;
integerPart = tmp >> 2;
dimmData.temp[0] = -1.0 * (integerPart + fractionalPart * 0.25);
}
else
{
dimmData.temp[0] = integerPart + fractionalPart * 0.25;
}
std::string i3cTS1Name = I3C_TS1_ADDR(cpuid) + to_hex(spd);
memset(rdBuf, 0, sizeof(rdBuf));
ret = i3cWriteRead(i3cTS1Name, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
integerPart = ((rdBuf[0] & 0xf0) >> 4) | ((rdBuf[1] & 0x0f) << 4);
fractionalPart = (rdBuf[0] & 0x0C) >> 2;
// check if a negative reading
if (rdBuf[1] & 0x10)
{
uint16_t tmp = (integerPart << 2) | fractionalPart;
tmp = ((~tmp) & 0x3ff) + 1;
fractionalPart = tmp & 0x3;
integerPart = tmp >> 2;
dimmData.temp[1] = -1.0 * (integerPart + fractionalPart * 0.25);
}
else
{
dimmData.temp[1] = integerPart + fractionalPart * 0.25;
}
return 0;
}
int DIMMSpdReader::getDIMMRegsVol(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
if constexpr (debug)
{
std::cout << "Start to get DIMM voltage "<< std::endl;
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
}
uint16_t wLen;
uint16_t rLen;
uint8_t adcSel[6] = {0x80, 0x88, 0x90, 0x98, 0xa0, 0xd0};
uint8_t adcOut[] = {0x31, 0};
uint8_t rdBuf[] = {0};
uint8_t wrBuf[3] = {0x30, 0, 0};
uint8_t adcValue = 0;
int pmic = NUM_TO_PMIC(rank);
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
rLen = 1;
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, &adcValue, rLen);
if (ret < 0)
{
return -1;
}
adcValue &= 0x7;
int adcValue10 = (int)(adcValue & 0x3);
adcDelay[cpuid][rank] = getADCUpdateTime(adcValue10);
int index = (pmicType[cpuid][rank] == PMIC5030) ? 6 : 4;
for(int i=0; i<index; i++) {
//Write R30
rLen = 0; //For Renesas requirements, I3C write commands cannot be directly read; reading requires a separate I3C command.
if(twoByteMode[cpuid][rank])
{
adcValue = 0x4; //PMIC5030 fixed the 2 byte mode + 1ms
wrBuf[2] = adcValue | adcSel[i];
wLen = 3;
}
else
{
wrBuf[1] = adcValue | adcSel[i];
wLen = 2;
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
// 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]));
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
rLen = 1;
rdBuf[0] = 0;
ret = i3cWriteRead(i3cPmicName, adcOut, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
dimmData.voltage[i] = rdBuf[0] * 15.0 / 1000.0;
}
return 0;
}
static double calStep31CurPower(int index, const uint8_t (&temp)[8])
{
if (index < 0 || index > 5)
return 0.0;
uint8_t reg;
uint8_t shift;
if(index < 4)
{
reg = temp[0];
shift = 6 - index * 2;
}
else
{
reg = temp[1];
shift = 6 - (index - 4) * 2;
}
uint8_t msb = (reg >> shift) & 0x03;
uint8_t lsb = temp[2 + index];
uint16_t raw10 = (static_cast<uint16_t>(msb) << 8) | lsb;
if constexpr (debug)
{
std::cout << "calStep31CurPower raw10: " << (int)raw10 << std::endl;
}
double result = std::round(raw10 * 31.25) / 1000.0;
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)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
if constexpr (debug)
{
std::cout << "Start to get DIMM current and power "<< std::endl;
std::cout << "pmicType[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)pmicType[cpuid][rank] << std::endl;
}
int index = 0;
uint16_t wLen;
uint16_t rLen = 1;
bool accStep31 = false;
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}; //For Renesas requirements, I3C command: Continuously read R100~R107
uint8_t wrBuf[] = {0, 0};
int pmic = NUM_TO_PMIC(rank);
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
if(pmicType[cpuid][rank] == PMIC5030)
{
uint8_t adcAcc[] = {0x32, 0};
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
ret = i3cWriteRead(i3cPmicName, adcAcc, wLen, rdBuf, rLen);
if (ret < 0)
{
//std::cerr << " read word data failed. \n";
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;
}
}
if(accStep31)
{
index = 8;
for(int i=0; i<index; i++)
{
curOut[i] = 0x100 + i;
}
}
else
{
index = 4;
for(int i=0; i<index; i++)
{
curOut[i] = 0xc + i;
}
}
wLen = twoByteMode[cpuid][rank] ? 2 : 1;
ret = i3cWriteRead(i3cPmicName, adcSelect, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
if(twoByteMode[cpuid][rank])
{
adcSelect[2] = rdBuf[0] & 0xbf; //Read current
wLen = 3;
}
else
{
adcSelect[1] = rdBuf[0] & 0xbf; //Read current
wLen = 2;
}
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)
{
return -1;
}
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
if(accStep31)
{
rLen = 8;
memset(rdBuf, 0, sizeof(rdBuf));
if(twoByteMode[cpuid][rank])
{
wrBuf[0] = static_cast<uint8_t>(curOut[0] & 0xFF);
wrBuf[1] = static_cast<uint8_t>((curOut[0] >> 8) & 0xFF);
wLen = 2;
}
else
{
if constexpr (debug)
{
std::cout << "twoByteMode[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)twoByteMode[cpuid][rank] << std::endl;
}
if(pmicType[cpuid][rank] == PMIC5030)
{
return -1;
}
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
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])
{
adcSelect[2] |= 0x40;
wLen = 3;
}
else
{
adcSelect[1] |= 0x40;
wLen = 2;
}
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)
{
return -1;
}
std::this_thread::sleep_for(std::chrono::milliseconds(adcDelay[cpuid][rank]));
// 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[0] & 0xFF);
wrBuf[1] = static_cast<uint8_t>((curOut[0] >> 8) & 0xFF);
wLen = 2;
}
else
{
if constexpr (debug)
{
std::cout << "twoByteMode[" << (int)cpuid << "][" << (int)rank << "] = "<< (int)twoByteMode[cpuid][rank] << std::endl;
}
if(pmicType[cpuid][rank] == PMIC5030)
{
return -1;
}
}
ret = i3cWriteRead(i3cPmicName, wrBuf, wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
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;
}
int DIMMSpdReader::getPmicStatusRegs(uint8_t cpuid, uint8_t rank, DimmData& dimmData)
{
int ret = -1;
if(cpuid >= MAX_CPU_ID || rank >= MAX_DIMM_RANK) return ret;
uint16_t wLen = 1;
uint16_t rLen = 1;
uint8_t reg[] = {0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb};
uint8_t rdBuf[] = {0};
int pmic = NUM_TO_PMIC(rank);
std::string i3cPmicName = I3C_ADDR(cpuid) + to_hex(pmic);
size_t index = sizeof(reg) / sizeof(reg[0]);
for(size_t i=0; i<index; i++) {
ret = i3cWriteRead(i3cPmicName, &reg[i], wLen, rdBuf, rLen);
if (ret < 0)
{
return -1;
}
dimmData.reg[i] = rdBuf[0];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
return 0;
}
void DIMMSpdReader::init()
{
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},
{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);
dimmDataTable.insert_or_assign(dimmName, std::move(dData));
pmicType[cpuid][i] = Unknown;
gotType[cpuid][i] = false;
twoByteMode[cpuid][i] = false;
}
}
regCounter = 0;
pmicCounter = 0;
updateDbus();
updateToDimmInfoFile();
}
void DIMMSpdReader::readDimmInfo()
{
int ret = -1;
for(int cpuid=0; cpuid<MAX_CPU_ID; cpuid++) {
for(int i=0; i<MAX_DIMM_RANK; i++) {
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) {
setGPIOToSelectDimm(cfgGPIO[index]);
lastIndex = index;
}
ret = getPmicType(cpuid, i);
if (ret < 0)
{
if constexpr (debug)
{
std::cerr << " get cpu" << cpuid << " rank" << i << " PMIC Type failed. \n";
}
}
ret = getDIMMRegsTemp(cpuid, i, dData);
if (ret < 0)
{
if constexpr (debug)
{
std::cerr << " read cpu" << cpuid << " rank" << i << " dimm temp failed. \n";
}
}
updateField(dimmName, TEMP, dData.temp, STATUS_TEMP_NUM);
#if 1
if(regCounter == 0)
{
ret = getPmicStatusRegs(cpuid, i, dData);
if (ret < 0)
{
if constexpr (debug)
{
std::cerr << " read cpu" << cpuid << " rank" << i << " status registers failed. \n";
}
}
updateField(dimmName, STATUS, dData.reg, STATUS_REG_NUM);
}
if(pmicCounter == 0)
{
ret = getDIMMRegsVol(cpuid, i, dData);
if (ret < 0)
{
if constexpr (debug)
{
std::cerr << " read cpu" << cpuid << " rank" << i << " dimm voltage failed. \n";
}
}
updateField(dimmName, VOLTAGE, dData.voltage, STATUS_PMIC_RAIL_NUM);
ret = getDIMMRegsCurAndPow(cpuid, i, dData);
if (ret < 0)
{
if constexpr (debug)
{
std::cerr << " read cpu" << cpuid << " rank" << i << " dimm current and power failed. \n";
}
}
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
}
}
return;
}
void DIMMSpdReader::updateDbus()
{
for(auto data : dimmDataTable) {
if(dimm_temp_inf.find(data.first) != dimm_temp_inf.end()) {
dimm_temp_inf[data.first]->set_property("TS0", data.second.temp[0]);
dimm_temp_inf[data.first]->set_property("TS1", data.second.temp[1]);
dimm_temp_inf[data.first]->set_property("SPD_TS", data.second.temp[2]);
}
if(dimm_voltage_inf.find(data.first) != dimm_voltage_inf.end()) {
dimm_voltage_inf[data.first]->set_property("SWA", data.second.voltage[0]);
dimm_voltage_inf[data.first]->set_property("SWB", data.second.voltage[1]);
dimm_voltage_inf[data.first]->set_property("SWC", data.second.voltage[2]);
dimm_voltage_inf[data.first]->set_property("SWD", data.second.voltage[3]);
dimm_voltage_inf[data.first]->set_property("SWE", data.second.voltage[4]);
dimm_voltage_inf[data.first]->set_property("SWF", data.second.voltage[5]);
}
if(dimm_current_inf.find(data.first) != dimm_current_inf.end()) {
dimm_current_inf[data.first]->set_property("SWA", data.second.current[0]);
dimm_current_inf[data.first]->set_property("SWB", data.second.current[1]);
dimm_current_inf[data.first]->set_property("SWC", data.second.current[2]);
dimm_current_inf[data.first]->set_property("SWD", data.second.current[3]);
dimm_current_inf[data.first]->set_property("SWE", data.second.current[4]);
dimm_current_inf[data.first]->set_property("SWF", data.second.current[5]);
}
if(dimm_power_inf.find(data.first) != dimm_power_inf.end()) {
dimm_power_inf[data.first]->set_property("SWA", data.second.power[0]);
dimm_power_inf[data.first]->set_property("SWB", data.second.power[1]);
dimm_power_inf[data.first]->set_property("SWC", data.second.power[2]);
dimm_power_inf[data.first]->set_property("SWD", data.second.power[3]);
dimm_power_inf[data.first]->set_property("SWE", data.second.power[4]);
dimm_power_inf[data.first]->set_property("SWF", data.second.power[5]);
}
if(dimm_statusReg_inf.find(data.first) != dimm_statusReg_inf.end()) {
dimm_statusReg_inf[data.first]->set_property("0x04", data.second.reg[0]);
dimm_statusReg_inf[data.first]->set_property("0x05", data.second.reg[1]);
dimm_statusReg_inf[data.first]->set_property("0x06", data.second.reg[2]);
dimm_statusReg_inf[data.first]->set_property("0x07", data.second.reg[3]);
dimm_statusReg_inf[data.first]->set_property("0x08", data.second.reg[4]);
dimm_statusReg_inf[data.first]->set_property("0x09", data.second.reg[5]);
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]);
}
}
}
void DIMMSpdReader::updateToDimmInfoFile()
{
const std::filesystem::path outputPath(dimmInfoPath);
std::ofstream jsonOutputFile(outputPath);
if (!jsonOutputFile.is_open()) {
std::cout << "Failed to open dimmInfo json file" << std::endl;
return;
}
nlohmann::json js;
std::string timestamp = get_current_timestamp();
js["Current Time"] = timestamp;
//std::cout << "timestamp: " << timestamp << std::endl;
for(auto data : dimmDataTable) {
//update temperature
js[data.first]["Temperature_DegreesC"]["TS0"] = data.second.temp[0];
js[data.first]["Temperature_DegreesC"]["TS1"] = data.second.temp[1];
js[data.first]["Temperature_DegreesC"]["SPD_TS"] = data.second.temp[2];
//update voltage
js[data.first]["Voltage_Volt"]["SWA"] = data.second.voltage[0];
js[data.first]["Voltage_Volt"]["SWB"] = data.second.voltage[1];
js[data.first]["Voltage_Volt"]["SWC"] = data.second.voltage[2];
js[data.first]["Voltage_Volt"]["SWD"] = data.second.voltage[3];
js[data.first]["Voltage_Volt"]["SWE"] = data.second.voltage[4];
js[data.first]["Voltage_Volt"]["SWF"] = data.second.voltage[5];
//update current
js[data.first]["Current_Ampere"]["SWA"] = data.second.current[0];
js[data.first]["Current_Ampere"]["SWB"] = data.second.current[1];
js[data.first]["Current_Ampere"]["SWC"] = data.second.current[2];
js[data.first]["Current_Ampere"]["SWD"] = data.second.current[3];
js[data.first]["Current_Ampere"]["SWE"] = data.second.current[4];
js[data.first]["Current_Ampere"]["SWF"] = data.second.current[5];
//update power
js[data.first]["Power_Watt"]["SWA"] = data.second.power[0];
js[data.first]["Power_Watt"]["SWB"] = data.second.power[1];
js[data.first]["Power_Watt"]["SWC"] = data.second.power[2];
js[data.first]["Power_Watt"]["SWD"] = data.second.power[3];
js[data.first]["Power_Watt"]["SWE"] = data.second.power[4];
js[data.first]["Power_Watt"]["SWF"] = data.second.power[5];
//update status registers
js[data.first]["Status_Reg"]["0x04"] = data.second.reg[0];
js[data.first]["Status_Reg"]["0x05"] = data.second.reg[1];
js[data.first]["Status_Reg"]["0x06"] = data.second.reg[2];
js[data.first]["Status_Reg"]["0x07"] = data.second.reg[3];
js[data.first]["Status_Reg"]["0x08"] = data.second.reg[4];
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);
return;
}
void DIMMSpdReader::setupMatches(sdbusplus::bus_t& connection)
{
std::weak_ptr<DIMMSpdReader> weakRef = weak_from_this();
std::shared_ptr<DIMMSpdReader> sharedRef = weakRef.lock();
dimmI3cSwitchMatcher(matches, connection, [sharedRef](bool state)
{
if (!sharedRef)
{
return;
}
if (!state)
{
//switch dimm i3c to bios
sharedRef->waitTimer.cancel();
sharedRef->init();
std::cout << "waitTimer canceled" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
int ret = system("rmmod dw-i3c-master");
if (ret != 0) {
std::cout << "Failed to rmmod dw-i3c-master module" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
else
{
int ret = system("modprobe dw-i3c-master");
if (ret != 0) {
std::cout << "Failed to modprobe dw-i3c-master module" << std::endl;
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
//switch dimm i3c to bmc
std::cout << "start to Read" << std::endl;
sharedRef->startRead();
}
});
}