blob: a82d5a6985c2cabc96590bd353bfc7abad34090a [file] [log] [blame]
#include "mps.hpp"
namespace phosphor::software::VR
{
bool MPSImageParser::isValidDataTokens(
const std::vector<std::string_view>& tokens)
{
return tokens.size() > static_cast<size_t>(ATE::regName) &&
!tokens[0].starts_with('*');
}
MPSData MPSImageParser::extractType0Data(
const std::vector<std::string_view>& tokens)
{
MPSData data;
static constexpr size_t type0TokensSize = 7;
if (tokens.size() != type0TokensSize)
{
lg2::error("Invalid token count for Type0 image line: "
"expected {EXPECTED}, got {ACTUAL}",
"EXPECTED", type0TokensSize, "ACTUAL", tokens.size());
return data;
}
data.page = getVal<uint8_t>(tokens, ATE::pageNum);
data.addr = getVal<uint8_t>(tokens, ATE::regAddrHex);
std::string regData = getVal<std::string>(tokens, ATE::regDataHex);
size_t byteCount = std::min(regData.length() / 2, size_t(4));
for (size_t i = 0; i < byteCount; ++i)
{
data.data[byteCount - 1 - i] = static_cast<uint8_t>(
std::stoul(regData.substr(i * 2, 2), nullptr, 16));
}
data.length = static_cast<uint8_t>(byteCount);
return data;
}
MPSData MPSImageParser::extractType1Data(
const std::vector<std::string_view>& tokens)
{
MPSData data;
static constexpr size_t type0TokensSize = 8;
if (tokens.size() != type0TokensSize)
{
lg2::error("Invalid token count for Type1 image line: "
"expected {EXPECTED}, got {ACTUAL}",
"EXPECTED", type0TokensSize, "ACTUAL", tokens.size());
return data;
}
data.page = getVal<uint8_t>(tokens, ATE::pageNum);
auto addr = getVal<uint16_t>(tokens, ATE::regAddrHex);
auto cmdType = getVal<std::string>(tokens, ATE::writeType);
int blockDataBytes = 0;
if (cmdType.starts_with("P"))
{
// Check if these tokens represent a P1 or P2 process call.
// The upper byte of 'addr' is the command code, and the lower byte
// is the LSB of the data.
// Example:
// addr = 0x0F11 and data = 0x18, this sends 0x1811 to command 0x0F
static constexpr uint16_t processCallAddrMask = 0xFF00;
data.data[0] = static_cast<uint8_t>(addr & ~processCallAddrMask);
data.data[1] = getVal<uint8_t>(tokens, ATE::regDataHex);
data.addr = static_cast<uint8_t>((addr & processCallAddrMask) >> 8);
data.length = 2;
return data;
}
else if (cmdType.starts_with("B"))
{
// Command types starting with 'B' indicate block r/w commands.
// The number following 'B' specifies the number of data bytes.
if (cmdType.size() > 1 && std::isdigit(cmdType[1]))
{
blockDataBytes = std::stoi(cmdType.substr(1));
}
}
std::string regData = getVal<std::string>(tokens, ATE::regDataHex);
size_t byteCount = std::min(regData.length() / 2, size_t(4));
size_t dataIndex = 0;
if (blockDataBytes > 0)
{
data.data[dataIndex++] = static_cast<uint8_t>(blockDataBytes);
}
for (size_t i = 0; i < byteCount; ++i)
{
data.data[dataIndex + (byteCount - 1 - i)] = static_cast<uint8_t>(
std::stoul(regData.substr(i * 2, 2), nullptr, 16));
}
data.length = static_cast<uint8_t>(dataIndex + byteCount);
data.addr = getVal<uint8_t>(tokens, ATE::regAddrHex);
return data;
}
std::vector<MPSData> MPSImageParser::parse(
const uint8_t* image, size_t imageSize, MPSImageType imageType)
{
lineTokens = TokenizedLines(image, imageSize);
std::vector<MPSData> results;
using ExtractDataFunc =
std::function<MPSData(const std::vector<std::string_view>&)>;
ExtractDataFunc extractDataFunc;
switch (imageType)
{
case MPSImageType::type0:
extractDataFunc = [this](const auto& tokens) {
return extractType0Data(tokens);
};
break;
case MPSImageType::type1:
extractDataFunc = [this](const auto& tokens) {
return extractType1Data(tokens);
};
break;
default:
lg2::error("Unsupported or unknown MPS image type: {TYPE}", "TYPE",
static_cast<int>(imageType));
return results;
}
for (const auto& tokens : lineTokens)
{
if (tokens[0].starts_with("END"))
{
break;
}
if (isValidDataTokens(tokens))
{
auto data = extractDataFunc(tokens);
if (data.length == 0)
{
return {};
}
results.push_back(data);
}
}
return results;
}
sdbusplus::async::task<bool> MPSVoltageRegulator::parseImage(
const uint8_t* image, size_t imageSize, MPSImageType imageType)
{
configuration = std::make_unique<MPSConfig>();
try
{
configuration->registersData =
parser->parse(image, imageSize, imageType);
if (!co_await parseDeviceConfiguration())
{
co_return false;
}
}
catch (const std::exception& e)
{
lg2::error("Failed to parse MPS image: {ERR}", "ERR", e.what());
co_return false;
}
lg2::debug(
"Parsed configuration: Data Size={SIZE}, Vendor ID={VID}, "
"Product ID={PID}, Config ID={CID}, CRC User={CRCUSR}, "
"CRC Multi={CRCMULTI}",
"SIZE", configuration->registersData.size(), "VID", lg2::hex,
configuration->vendorId, "PID", lg2::hex, configuration->productId,
"CID", lg2::hex, configuration->configId, "CRCUSR", lg2::hex,
configuration->crcUser, "CRCMULTI", lg2::hex, configuration->crcMulti);
co_return true;
}
std::map<uint8_t, std::vector<MPSData>>
MPSVoltageRegulator::getGroupedConfigData(uint8_t configMask, uint8_t shift)
{
std::map<uint8_t, std::vector<MPSData>> groupedData;
if (!configuration)
{
return groupedData;
}
for (const auto& data : configuration->registersData)
{
uint8_t config = (data.page & configMask) >> shift;
groupedData[config].push_back(data);
}
return groupedData;
}
} // namespace phosphor::software::VR