blob: a82d5a6985c2cabc96590bd353bfc7abad34090a [file] [log] [blame]
Kevin Tungdcf4b602025-07-04 13:14:49 +08001#include "mps.hpp"
2
3namespace phosphor::software::VR
4{
5
6bool MPSImageParser::isValidDataTokens(
7 const std::vector<std::string_view>& tokens)
8{
9 return tokens.size() > static_cast<size_t>(ATE::regName) &&
10 !tokens[0].starts_with('*');
11}
12
Kevin Tungc284e752025-10-14 20:47:09 +080013MPSData MPSImageParser::extractType0Data(
14 const std::vector<std::string_view>& tokens)
Kevin Tungdcf4b602025-07-04 13:14:49 +080015{
16 MPSData data;
Kevin Tungc284e752025-10-14 20:47:09 +080017 static constexpr size_t type0TokensSize = 7;
18
19 if (tokens.size() != type0TokensSize)
20 {
21 lg2::error("Invalid token count for Type0 image line: "
22 "expected {EXPECTED}, got {ACTUAL}",
23 "EXPECTED", type0TokensSize, "ACTUAL", tokens.size());
24 return data;
25 }
26
Kevin Tungdcf4b602025-07-04 13:14:49 +080027 data.page = getVal<uint8_t>(tokens, ATE::pageNum);
28 data.addr = getVal<uint8_t>(tokens, ATE::regAddrHex);
29
30 std::string regData = getVal<std::string>(tokens, ATE::regDataHex);
31 size_t byteCount = std::min(regData.length() / 2, size_t(4));
32 for (size_t i = 0; i < byteCount; ++i)
33 {
34 data.data[byteCount - 1 - i] = static_cast<uint8_t>(
35 std::stoul(regData.substr(i * 2, 2), nullptr, 16));
36 }
37
38 data.length = static_cast<uint8_t>(byteCount);
39 return data;
40}
41
Kevin Tungc284e752025-10-14 20:47:09 +080042MPSData MPSImageParser::extractType1Data(
43 const std::vector<std::string_view>& tokens)
Kevin Tungdcf4b602025-07-04 13:14:49 +080044{
Kevin Tungc284e752025-10-14 20:47:09 +080045 MPSData data;
46 static constexpr size_t type0TokensSize = 8;
47
48 if (tokens.size() != type0TokensSize)
49 {
50 lg2::error("Invalid token count for Type1 image line: "
51 "expected {EXPECTED}, got {ACTUAL}",
52 "EXPECTED", type0TokensSize, "ACTUAL", tokens.size());
53 return data;
54 }
55
56 data.page = getVal<uint8_t>(tokens, ATE::pageNum);
57 auto addr = getVal<uint16_t>(tokens, ATE::regAddrHex);
58 auto cmdType = getVal<std::string>(tokens, ATE::writeType);
59 int blockDataBytes = 0;
60
61 if (cmdType.starts_with("P"))
62 {
63 // Check if these tokens represent a P1 or P2 process call.
64 // The upper byte of 'addr' is the command code, and the lower byte
65 // is the LSB of the data.
66 // Example:
67 // addr = 0x0F11 and data = 0x18, this sends 0x1811 to command 0x0F
68 static constexpr uint16_t processCallAddrMask = 0xFF00;
69 data.data[0] = static_cast<uint8_t>(addr & ~processCallAddrMask);
70 data.data[1] = getVal<uint8_t>(tokens, ATE::regDataHex);
71 data.addr = static_cast<uint8_t>((addr & processCallAddrMask) >> 8);
72 data.length = 2;
73 return data;
74 }
75 else if (cmdType.starts_with("B"))
76 {
77 // Command types starting with 'B' indicate block r/w commands.
78 // The number following 'B' specifies the number of data bytes.
79 if (cmdType.size() > 1 && std::isdigit(cmdType[1]))
80 {
81 blockDataBytes = std::stoi(cmdType.substr(1));
82 }
83 }
84
85 std::string regData = getVal<std::string>(tokens, ATE::regDataHex);
86 size_t byteCount = std::min(regData.length() / 2, size_t(4));
87 size_t dataIndex = 0;
88
89 if (blockDataBytes > 0)
90 {
91 data.data[dataIndex++] = static_cast<uint8_t>(blockDataBytes);
92 }
93
94 for (size_t i = 0; i < byteCount; ++i)
95 {
96 data.data[dataIndex + (byteCount - 1 - i)] = static_cast<uint8_t>(
97 std::stoul(regData.substr(i * 2, 2), nullptr, 16));
98 }
99 data.length = static_cast<uint8_t>(dataIndex + byteCount);
100 data.addr = getVal<uint8_t>(tokens, ATE::regAddrHex);
101 return data;
102}
103
104std::vector<MPSData> MPSImageParser::parse(
105 const uint8_t* image, size_t imageSize, MPSImageType imageType)
106{
107 lineTokens = TokenizedLines(image, imageSize);
108 std::vector<MPSData> results;
109
110 using ExtractDataFunc =
111 std::function<MPSData(const std::vector<std::string_view>&)>;
112 ExtractDataFunc extractDataFunc;
113
114 switch (imageType)
115 {
116 case MPSImageType::type0:
117 extractDataFunc = [this](const auto& tokens) {
118 return extractType0Data(tokens);
119 };
120 break;
121 case MPSImageType::type1:
122 extractDataFunc = [this](const auto& tokens) {
123 return extractType1Data(tokens);
124 };
125 break;
126 default:
127 lg2::error("Unsupported or unknown MPS image type: {TYPE}", "TYPE",
128 static_cast<int>(imageType));
129 return results;
130 }
131
Kevin Tungdcf4b602025-07-04 13:14:49 +0800132 for (const auto& tokens : lineTokens)
133 {
134 if (tokens[0].starts_with("END"))
135 {
136 break;
137 }
138
139 if (isValidDataTokens(tokens))
140 {
Kevin Tungc284e752025-10-14 20:47:09 +0800141 auto data = extractDataFunc(tokens);
142 if (data.length == 0)
143 {
144 return {};
145 }
146 results.push_back(data);
Kevin Tungdcf4b602025-07-04 13:14:49 +0800147 }
148 }
Kevin Tungc284e752025-10-14 20:47:09 +0800149
150 return results;
Kevin Tungdcf4b602025-07-04 13:14:49 +0800151}
152
153sdbusplus::async::task<bool> MPSVoltageRegulator::parseImage(
Kevin Tungc284e752025-10-14 20:47:09 +0800154 const uint8_t* image, size_t imageSize, MPSImageType imageType)
Kevin Tungdcf4b602025-07-04 13:14:49 +0800155{
Kevin Tungdcf4b602025-07-04 13:14:49 +0800156 configuration = std::make_unique<MPSConfig>();
Kevin Tungdcf4b602025-07-04 13:14:49 +0800157
Kevin Tungc284e752025-10-14 20:47:09 +0800158 try
Kevin Tungdcf4b602025-07-04 13:14:49 +0800159 {
Kevin Tungc284e752025-10-14 20:47:09 +0800160 configuration->registersData =
161 parser->parse(image, imageSize, imageType);
162
163 if (!co_await parseDeviceConfiguration())
164 {
165 co_return false;
166 }
167 }
168 catch (const std::exception& e)
169 {
170 lg2::error("Failed to parse MPS image: {ERR}", "ERR", e.what());
Kevin Tungdcf4b602025-07-04 13:14:49 +0800171 co_return false;
172 }
173
174 lg2::debug(
175 "Parsed configuration: Data Size={SIZE}, Vendor ID={VID}, "
176 "Product ID={PID}, Config ID={CID}, CRC User={CRCUSR}, "
177 "CRC Multi={CRCMULTI}",
178 "SIZE", configuration->registersData.size(), "VID", lg2::hex,
179 configuration->vendorId, "PID", lg2::hex, configuration->productId,
180 "CID", lg2::hex, configuration->configId, "CRCUSR", lg2::hex,
181 configuration->crcUser, "CRCMULTI", lg2::hex, configuration->crcMulti);
182
183 co_return true;
184}
185
186std::map<uint8_t, std::vector<MPSData>>
187 MPSVoltageRegulator::getGroupedConfigData(uint8_t configMask, uint8_t shift)
188{
189 std::map<uint8_t, std::vector<MPSData>> groupedData;
190
191 if (!configuration)
192 {
193 return groupedData;
194 }
195
196 for (const auto& data : configuration->registersData)
197 {
198 uint8_t config = (data.page & configMask) >> shift;
199 groupedData[config].push_back(data);
200 }
201
202 return groupedData;
203}
204
205} // namespace phosphor::software::VR